1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security auditing functions 5 * COPYRIGHT: Copyright Eric Kohl 6 * Copyright Timo Kreuzer <timo.kreuzer@reactos.org> 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #define SEP_PRIVILEGE_SET_MAX_COUNT 60 16 17 UNICODE_STRING SeSubsystemName = RTL_CONSTANT_STRING(L"Security"); 18 19 /* PRIVATE FUNCTIONS***********************************************************/ 20 21 /** 22 * @unimplemented 23 * @brief 24 * Peforms a detailed security auditing with an access token. 25 * 26 * @param[in] Token 27 * A valid token object. 28 * 29 * @return 30 * To be added... 31 */ 32 BOOLEAN 33 NTAPI 34 SeDetailedAuditingWithToken( 35 _In_ PTOKEN Token) 36 { 37 /* FIXME */ 38 return FALSE; 39 } 40 41 /** 42 * @unimplemented 43 * @brief 44 * Peforms a security auditing against a process that is about to 45 * be created. 46 * 47 * @param[in] Process 48 * An object that points to a process which is in process of 49 * creation. 50 * 51 * @return 52 * Nothing. 53 */ 54 VOID 55 NTAPI 56 SeAuditProcessCreate( 57 _In_ PEPROCESS Process) 58 { 59 /* FIXME */ 60 } 61 62 /** 63 * @unimplemented 64 * @brief 65 * Peforms a security auditing against a process that is about to 66 * be terminated. 67 * 68 * @param[in] Process 69 * An object that points to a process which is in process of 70 * termination. 71 * 72 * @return 73 * Nothing. 74 */ 75 VOID 76 NTAPI 77 SeAuditProcessExit( 78 _In_ PEPROCESS Process) 79 { 80 /* FIXME */ 81 } 82 83 /** 84 * @brief 85 * Initializes a process audit name and returns it to the caller. 86 * 87 * @param[in] FileObject 88 * File object that points to a name to be queried. 89 * 90 * @param[in] DoAudit 91 * If set to TRUE, the function will perform various security 92 * auditing onto the audit name. 93 * 94 * @param[out] AuditInfo 95 * The returned audit info data. 96 * 97 * @return 98 * Returns STATUS_SUCCESS if process audit name initialization 99 * has completed successfully. STATUS_NO_MEMORY is returned if 100 * pool allocation for object name info has failed. A failure 101 * NTSTATUS code is returned otherwise. 102 */ 103 NTSTATUS 104 NTAPI 105 SeInitializeProcessAuditName( 106 _In_ PFILE_OBJECT FileObject, 107 _In_ BOOLEAN DoAudit, 108 _Out_ POBJECT_NAME_INFORMATION *AuditInfo) 109 { 110 OBJECT_NAME_INFORMATION LocalNameInfo; 111 POBJECT_NAME_INFORMATION ObjectNameInfo = NULL; 112 ULONG ReturnLength = 8; 113 NTSTATUS Status; 114 115 PAGED_CODE(); 116 ASSERT(AuditInfo); 117 118 /* Check if we should do auditing */ 119 if (DoAudit) 120 { 121 /* FIXME: TODO */ 122 } 123 124 /* Now query the name */ 125 Status = ObQueryNameString(FileObject, 126 &LocalNameInfo, 127 sizeof(LocalNameInfo), 128 &ReturnLength); 129 if (((Status == STATUS_BUFFER_OVERFLOW) || 130 (Status == STATUS_BUFFER_TOO_SMALL) || 131 (Status == STATUS_INFO_LENGTH_MISMATCH)) && 132 (ReturnLength != sizeof(LocalNameInfo))) 133 { 134 /* Allocate required size */ 135 ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool, 136 ReturnLength, 137 TAG_SEPA); 138 if (ObjectNameInfo) 139 { 140 /* Query the name again */ 141 Status = ObQueryNameString(FileObject, 142 ObjectNameInfo, 143 ReturnLength, 144 &ReturnLength); 145 } 146 } 147 148 /* Check if we got here due to failure */ 149 if ((ObjectNameInfo) && 150 (!(NT_SUCCESS(Status)) || (ReturnLength == sizeof(LocalNameInfo)))) 151 { 152 /* First, free any buffer we might've allocated */ 153 ASSERT(FALSE); 154 if (ObjectNameInfo) ExFreePool(ObjectNameInfo); 155 156 /* Now allocate a temporary one */ 157 ReturnLength = sizeof(OBJECT_NAME_INFORMATION); 158 ObjectNameInfo = ExAllocatePoolWithTag(NonPagedPool, 159 sizeof(OBJECT_NAME_INFORMATION), 160 TAG_SEPA); 161 if (ObjectNameInfo) 162 { 163 /* Clear it */ 164 RtlZeroMemory(ObjectNameInfo, ReturnLength); 165 Status = STATUS_SUCCESS; 166 } 167 } 168 169 /* Check if memory allocation failed */ 170 if (!ObjectNameInfo) Status = STATUS_NO_MEMORY; 171 172 /* Return the audit name */ 173 *AuditInfo = ObjectNameInfo; 174 175 /* Return status */ 176 return Status; 177 } 178 179 /** 180 * @brief 181 * Finds the process image name of a specific process. 182 * 183 * @param[in] Process 184 * Process object submitted by the caller, where the image name 185 * is to be located. 186 * 187 * @param[out] ProcessImageName 188 * An output Unicode string structure with the located process 189 * image name. 190 * 191 * @return 192 * Returns STATUS_SUCCESS if process image name has been located 193 * successfully. STATUS_NO_MEMORY is returned if pool allocation 194 * for the image name has failed. A failure NTSTATUS code is 195 * returned otherwise. 196 */ 197 NTSTATUS 198 NTAPI 199 SeLocateProcessImageName( 200 _In_ PEPROCESS Process, 201 _Out_ PUNICODE_STRING *ProcessImageName) 202 { 203 POBJECT_NAME_INFORMATION AuditName; 204 PUNICODE_STRING ImageName; 205 PFILE_OBJECT FileObject; 206 NTSTATUS Status = STATUS_SUCCESS; 207 208 PAGED_CODE(); 209 210 /* Assume failure */ 211 *ProcessImageName = NULL; 212 213 /* Check if we have audit info */ 214 AuditName = Process->SeAuditProcessCreationInfo.ImageFileName; 215 if (!AuditName) 216 { 217 /* Get the file object */ 218 Status = PsReferenceProcessFilePointer(Process, &FileObject); 219 if (!NT_SUCCESS(Status)) return Status; 220 221 /* Initialize the audit structure */ 222 Status = SeInitializeProcessAuditName(FileObject, TRUE, &AuditName); 223 if (NT_SUCCESS(Status)) 224 { 225 /* Set it */ 226 if (InterlockedCompareExchangePointer((PVOID*)&Process-> 227 SeAuditProcessCreationInfo.ImageFileName, 228 AuditName, 229 NULL)) 230 { 231 /* Someone beat us to it, deallocate our copy */ 232 ExFreePool(AuditName); 233 } 234 } 235 236 /* Dereference the file object */ 237 ObDereferenceObject(FileObject); 238 if (!NT_SUCCESS(Status)) return Status; 239 } 240 241 /* Get audit info again, now we have it for sure */ 242 AuditName = Process->SeAuditProcessCreationInfo.ImageFileName; 243 244 /* Allocate the output string */ 245 ImageName = ExAllocatePoolWithTag(NonPagedPool, 246 AuditName->Name.MaximumLength + 247 sizeof(UNICODE_STRING), 248 TAG_SEPA); 249 if (!ImageName) return STATUS_NO_MEMORY; 250 251 /* Make a copy of it */ 252 RtlCopyMemory(ImageName, 253 &AuditName->Name, 254 AuditName->Name.MaximumLength + sizeof(UNICODE_STRING)); 255 256 /* Fix up the buffer */ 257 ImageName->Buffer = (PWSTR)(ImageName + 1); 258 259 /* Return it */ 260 *ProcessImageName = ImageName; 261 262 /* Return status */ 263 return Status; 264 } 265 266 /** 267 * @brief 268 * Closes an audit alarm event of an object. 269 * 270 * @param[in] SubsystemName 271 * A Unicode string pointing to the name of the subsystem where auditing 272 * alarm event has to be closed. 273 * 274 * @param[in] HandleId 275 * A handle to an ID where such ID represents the identification of the 276 * object where audit alarm is to be closed. 277 * 278 * @param[in] Sid 279 * A SID that represents the user who attempted to close the audit 280 * alarm. 281 * 282 * @return 283 * Nothing. 284 */ 285 VOID 286 NTAPI 287 SepAdtCloseObjectAuditAlarm( 288 _In_ PUNICODE_STRING SubsystemName, 289 _In_ PVOID HandleId, 290 _In_ PSID Sid) 291 { 292 UNIMPLEMENTED; 293 } 294 295 /** 296 * @brief 297 * Performs an audit alarm to a privileged service request. 298 * This is a worker function. 299 * 300 * @param[in] SubjectContext 301 * A security subject context used for the auditing process. 302 * 303 * @param[in] SubsystemName 304 * A Unicode string that represents the name of a subsystem that 305 * actuated the procedure of alarm auditing of a privileged 306 * service. 307 * 308 * @param[in] ServiceName 309 * A Unicode string that represents the name of a privileged 310 * service request for auditing. 311 * 312 * @param[in] Token 313 * An access token. 314 * 315 * @param[in] PrimaryToken 316 * A primary access token. 317 * 318 * @param[in] Privileges 319 * An array set of privileges used to check if the privileged 320 * service does actually have all the required set of privileges 321 * for security access. 322 * 323 * @param[in] AccessGranted 324 * When auditing is done, the function will return TRUE to the caller 325 * if access is granted, FALSE otherwise. 326 * 327 * @return 328 * Nothing. 329 */ 330 VOID 331 NTAPI 332 SepAdtPrivilegedServiceAuditAlarm( 333 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 334 _In_opt_ PUNICODE_STRING SubsystemName, 335 _In_opt_ PUNICODE_STRING ServiceName, 336 _In_ PTOKEN Token, 337 _In_ PTOKEN PrimaryToken, 338 _In_ PPRIVILEGE_SET Privileges, 339 _In_ BOOLEAN AccessGranted) 340 { 341 DPRINT("SepAdtPrivilegedServiceAuditAlarm is unimplemented\n"); 342 } 343 344 /** 345 * @brief 346 * Performs an audit alarm to a privileged service request. 347 * 348 * @param[in] ServiceName 349 * A Unicode string that represents the name of a privileged 350 * service request for auditing. 351 * 352 * @param[in] SubjectContext 353 * A security subject context used for the auditing process. 354 * 355 * @param[in] PrivilegeSet 356 * An array set of privileges used to check if the privileged 357 * service does actually have all the required set of privileges 358 * for security access. 359 * 360 * @param[in] AccessGranted 361 * When auditing is done, the function will return TRUE to the caller 362 * if access is granted, FALSE otherwise. 363 * 364 * @return 365 * Nothing. 366 */ 367 VOID 368 NTAPI 369 SePrivilegedServiceAuditAlarm( 370 _In_opt_ PUNICODE_STRING ServiceName, 371 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 372 _In_ PPRIVILEGE_SET PrivilegeSet, 373 _In_ BOOLEAN AccessGranted) 374 { 375 PTOKEN EffectiveToken; 376 PSID UserSid; 377 PAGED_CODE(); 378 379 /* Get the effective token */ 380 if (SubjectContext->ClientToken != NULL) 381 EffectiveToken = SubjectContext->ClientToken; 382 else 383 EffectiveToken = SubjectContext->PrimaryToken; 384 385 /* Get the user SID */ 386 UserSid = EffectiveToken->UserAndGroups->Sid; 387 388 /* Check if this is the local system SID */ 389 if (RtlEqualSid(UserSid, SeLocalSystemSid)) 390 { 391 /* Nothing to do */ 392 return; 393 } 394 395 /* Check if this is the network service or local service SID */ 396 if (RtlEqualSid(UserSid, SeExports->SeNetworkServiceSid) || 397 RtlEqualSid(UserSid, SeExports->SeLocalServiceSid)) 398 { 399 // FIXME: should continue for a certain set of privileges 400 return; 401 } 402 403 /* Call the worker function */ 404 SepAdtPrivilegedServiceAuditAlarm(SubjectContext, 405 &SeSubsystemName, 406 ServiceName, 407 SubjectContext->ClientToken, 408 SubjectContext->PrimaryToken, 409 PrivilegeSet, 410 AccessGranted); 411 412 } 413 414 /** 415 * @brief 416 * Captures a list of object types. 417 * 418 * @param[in] ObjectTypeList 419 * An existing list of object types. 420 * 421 * @param[in] ObjectTypeListLength 422 * The length size of the list. 423 * 424 * @param[in] PreviousMode 425 * Processor access level mode. 426 * 427 * @param[out] CapturedObjectTypeList 428 * The captured list of object types. 429 * 430 * @return 431 * Returns STATUS_SUCCESS if the list of object types has been captured 432 * successfully. STATUS_INVALID_PARAMETER is returned if the caller hasn't 433 * supplied a buffer list of object types. STATUS_INSUFFICIENT_RESOURCES 434 * is returned if pool memory allocation for the captured list has failed. 435 */ 436 static 437 NTSTATUS 438 SeCaptureObjectTypeList( 439 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 440 _In_ ULONG ObjectTypeListLength, 441 _In_ KPROCESSOR_MODE PreviousMode, 442 _Out_ POBJECT_TYPE_LIST *CapturedObjectTypeList) 443 { 444 SIZE_T Size; 445 446 if (PreviousMode == KernelMode) 447 { 448 return STATUS_NOT_IMPLEMENTED; 449 } 450 451 if (ObjectTypeListLength == 0) 452 { 453 *CapturedObjectTypeList = NULL; 454 return STATUS_SUCCESS; 455 } 456 457 if (ObjectTypeList == NULL) 458 { 459 return STATUS_INVALID_PARAMETER; 460 } 461 462 /* Calculate the list size and check for integer overflow */ 463 Size = ObjectTypeListLength * sizeof(OBJECT_TYPE_LIST); 464 if (Size == 0) 465 { 466 return STATUS_INVALID_PARAMETER; 467 } 468 469 /* Allocate a new list */ 470 *CapturedObjectTypeList = ExAllocatePoolWithTag(PagedPool, Size, TAG_SEPA); 471 if (*CapturedObjectTypeList == NULL) 472 { 473 return STATUS_INSUFFICIENT_RESOURCES; 474 } 475 476 _SEH2_TRY 477 { 478 ProbeForRead(ObjectTypeList, Size, sizeof(ULONG)); 479 RtlCopyMemory(*CapturedObjectTypeList, ObjectTypeList, Size); 480 } 481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 482 { 483 ExFreePoolWithTag(*CapturedObjectTypeList, TAG_SEPA); 484 *CapturedObjectTypeList = NULL; 485 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 486 } 487 _SEH2_END; 488 489 return STATUS_SUCCESS; 490 } 491 492 /** 493 * @brief 494 * Releases a buffer list of object types. 495 * 496 * @param[in] CapturedObjectTypeList 497 * A list of object types to free. 498 * 499 * @param[in] PreviousMode 500 * Processor access level mode. 501 * 502 * @return 503 * Nothing. 504 */ 505 static 506 VOID 507 SeReleaseObjectTypeList( 508 _In_ _Post_invalid_ POBJECT_TYPE_LIST CapturedObjectTypeList, 509 _In_ KPROCESSOR_MODE PreviousMode) 510 { 511 if ((PreviousMode != KernelMode) && (CapturedObjectTypeList != NULL)) 512 ExFreePoolWithTag(CapturedObjectTypeList, TAG_SEPA); 513 } 514 515 /** 516 * @unimplemented 517 * @brief 518 * Worker function that serves as the main heart and brain of the whole 519 * concept and implementation of auditing in the kernel. 520 * 521 * @param[in] SubsystemName 522 * A Unicode string that represents the name of a subsystem that 523 * actuates the auditing process. 524 * 525 * @param[in] HandleId 526 * A handle to an ID used to identify an object where auditing 527 * is to be done. 528 * 529 * @param[in] SubjectContext 530 * Security subject context. 531 * 532 * @param[in] ObjectTypeName 533 * A Unicode string that represents the name of an object type. 534 * 535 * @param[in] ObjectName 536 * The name of the object. 537 * 538 * @param[in] SecurityDescriptor 539 * A security descriptor with internal security information details 540 * for audit. 541 * 542 * @param[in] PrincipalSelfSid 543 * A principal self user SID. 544 * 545 * @param[in] DesiredAccess 546 * The desired access rights masks requested by the caller. 547 * 548 * @param[in] AuditType 549 * Type of audit to start. This parameter influences how an audit 550 * should be done. 551 * 552 * @param[in] HaveAuditPrivilege 553 * If set to TRUE, the security subject context has the audit privilege thus 554 * it is allowed the ability to perform the audit. 555 * 556 * @param[in] ObjectTypeList 557 * A list of object types. 558 * 559 * @param[in] ObjectTypeListLength 560 * The length size of the list. 561 * 562 * @param[in] GenericMapping 563 * The generic mapping table of access rights used whilst performing auditing 564 * sequence procedure. 565 * 566 * @param[out] GrantedAccessList 567 * This parameter is used to return to the caller a list of actual granted access 568 * rights masks that the audited object has. 569 * 570 * @param[out] AccessStatusList 571 * This parameter is used to return to the caller a list of status return codes. 572 * The function may actually return a single NTSTATUS code if the calling thread 573 * sets UseResultList parameter to FALSE. 574 * 575 * @param[out] GenerateOnClose 576 * Returns TRUE if the function has generated a list of granted access rights and 577 * status codes on termination, FALSE otherwise. 578 * 579 * @param[in] UseResultList 580 * If set to TRUE, the caller wants that the function should only return a single 581 * NTSTATUS code. 582 * 583 * @return 584 * Returns STATUS_SUCCESS if the function has completed the whole internal 585 * auditing procedure mechanism with success. 586 */ 587 _Must_inspect_result_ 588 static 589 NTSTATUS 590 SepAccessCheckAndAuditAlarmWorker( 591 _In_ PUNICODE_STRING SubsystemName, 592 _In_opt_ PVOID HandleId, 593 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 594 _In_ PUNICODE_STRING ObjectTypeName, 595 _In_ PUNICODE_STRING ObjectName, 596 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 597 _In_opt_ PSID PrincipalSelfSid, 598 _In_ ACCESS_MASK DesiredAccess, 599 _In_ AUDIT_EVENT_TYPE AuditType, 600 _In_ BOOLEAN HaveAuditPrivilege, 601 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 602 _In_ ULONG ObjectTypeListLength, 603 _In_ PGENERIC_MAPPING GenericMapping, 604 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList, 605 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList, 606 _Out_ PBOOLEAN GenerateOnClose, 607 _In_ BOOLEAN UseResultList) 608 { 609 ULONG ResultListLength, i; 610 611 /* Get the length of the result list */ 612 ResultListLength = UseResultList ? ObjectTypeListLength : 1; 613 614 /// FIXME: we should do some real work here... 615 UNIMPLEMENTED; 616 617 /// HACK: we just pretend all access is granted! 618 for (i = 0; i < ResultListLength; i++) 619 { 620 GrantedAccessList[i] = DesiredAccess; 621 AccessStatusList[i] = STATUS_SUCCESS; 622 } 623 624 *GenerateOnClose = FALSE; 625 626 return STATUS_SUCCESS; 627 } 628 629 /** 630 * @brief 631 * Performs security auditing, if the specific object can be granted 632 * security access or not. 633 * 634 * @param[in] SubsystemName 635 * A Unicode string that represents the name of a subsystem that 636 * actuates the auditing process. 637 * 638 * @param[in] HandleId 639 * A handle to an ID used to identify an object where auditing 640 * is to be done. 641 * 642 * @param[in] SubjectContext 643 * Security subject context. 644 * 645 * @param[in] ObjectTypeName 646 * A Unicode string that represents the name of an object type. 647 * 648 * @param[in] ObjectName 649 * The name of the object. 650 * 651 * @param[in] SecurityDescriptor 652 * A security descriptor with internal security information details 653 * for audit. 654 * 655 * @param[in] PrincipalSelfSid 656 * A principal self user SID. 657 * 658 * @param[in] DesiredAccess 659 * The desired access rights masks requested by the caller. 660 * 661 * @param[in] AuditType 662 * Type of audit to start. This parameter influences how an audit 663 * should be done. 664 * 665 * @param[in] Flags 666 * Flag bitmask parameter. 667 * 668 * @param[in] HaveAuditPrivilege 669 * If set to TRUE, the security subject context has the audit privilege thus 670 * it is allowed the ability to perform the audit. 671 * 672 * @param[in] ObjectTypeList 673 * A list of object types. 674 * 675 * @param[in] ObjectTypeListLength 676 * The length size of the list. 677 * 678 * @param[in] GenericMapping 679 * The generic mapping table of access rights used whilst performing auditing 680 * sequence procedure. 681 * 682 * @param[out] GrantedAccessList 683 * This parameter is used to return to the caller a list of actual granted access 684 * rights masks that the audited object has. 685 * 686 * @param[out] AccessStatusList 687 * This parameter is used to return to the caller a list of status return codes. 688 * The function may actually return a single NTSTATUS code if the calling thread 689 * sets UseResultList parameter to FALSE. 690 * 691 * @param[out] GenerateOnClose 692 * Returns TRUE if the function has generated a list of granted access rights and 693 * status codes on termination, FALSE otherwise. 694 * 695 * @param[in] UseResultList 696 * If set to TRUE, the caller wants that the function should only return a single 697 * NTSTATUS code. 698 * 699 * @return 700 * Returns STATUS_SUCCESS if the function has completed the whole internal 701 * auditing procedure mechanism with success. STATUS_INVALID_PARAMETER is 702 * returned if one of the parameters do not satisfy the general requirements 703 * by the function. STATUS_INSUFFICIENT_RESOURCES is returned if pool memory 704 * allocation has failed. STATUS_PRIVILEGE_NOT_HELD is returned if the current 705 * security subject context does not have the required audit privilege to actually 706 * perform auditing in the first place. STATUS_INVALID_SECURITY_DESCR is returned 707 * if the security descriptor provided by the caller is not valid, that is, such 708 * descriptor doesn't belong to the main user (owner) and current group. 709 * STATUS_GENERIC_NOT_MAPPED is returned if the access rights masks aren't actually 710 * mapped. A failure NTSTATUS code is returned otherwise. 711 */ 712 _Must_inspect_result_ 713 NTSTATUS 714 NTAPI 715 SepAccessCheckAndAuditAlarm( 716 _In_ PUNICODE_STRING SubsystemName, 717 _In_opt_ PVOID HandleId, 718 _In_ PHANDLE ClientTokenHandle, 719 _In_ PUNICODE_STRING ObjectTypeName, 720 _In_ PUNICODE_STRING ObjectName, 721 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 722 _In_opt_ PSID PrincipalSelfSid, 723 _In_ ACCESS_MASK DesiredAccess, 724 _In_ AUDIT_EVENT_TYPE AuditType, 725 _In_ ULONG Flags, 726 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 727 _In_ ULONG ObjectTypeListLength, 728 _In_ PGENERIC_MAPPING GenericMapping, 729 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList, 730 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList, 731 _Out_ PBOOLEAN GenerateOnClose, 732 _In_ BOOLEAN UseResultList) 733 { 734 SECURITY_SUBJECT_CONTEXT SubjectContext; 735 ULONG ResultListLength; 736 GENERIC_MAPPING LocalGenericMapping; 737 PTOKEN SubjectContextToken, ClientToken; 738 BOOLEAN AllocatedResultLists; 739 BOOLEAN HaveAuditPrivilege; 740 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor; 741 UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName; 742 ACCESS_MASK GrantedAccess, *SafeGrantedAccessList; 743 NTSTATUS AccessStatus, *SafeAccessStatusList; 744 PSID CapturedPrincipalSelfSid; 745 POBJECT_TYPE_LIST CapturedObjectTypeList; 746 ULONG i; 747 BOOLEAN LocalGenerateOnClose; 748 NTSTATUS Status; 749 PAGED_CODE(); 750 751 /* Only user mode is supported! */ 752 ASSERT(ExGetPreviousMode() != KernelMode); 753 754 /* Start clean */ 755 AllocatedResultLists = FALSE; 756 ClientToken = NULL; 757 CapturedSecurityDescriptor = NULL; 758 CapturedSubsystemName.Buffer = NULL; 759 CapturedObjectTypeName.Buffer = NULL; 760 CapturedObjectName.Buffer = NULL; 761 CapturedPrincipalSelfSid = NULL; 762 CapturedObjectTypeList = NULL; 763 764 /* Validate AuditType */ 765 if ((AuditType != AuditEventObjectAccess) && 766 (AuditType != AuditEventDirectoryServiceAccess)) 767 { 768 DPRINT1("Invalid audit type: %u\n", AuditType); 769 return STATUS_INVALID_PARAMETER; 770 } 771 772 /* Capture the security subject context */ 773 SeCaptureSubjectContext(&SubjectContext); 774 775 /* Did the caller pass a token handle? */ 776 if (ClientTokenHandle == NULL) 777 { 778 /* Check if we have a token in the subject context */ 779 if (SubjectContext.ClientToken == NULL) 780 { 781 Status = STATUS_NO_IMPERSONATION_TOKEN; 782 DPRINT1("No token\n"); 783 goto Cleanup; 784 } 785 786 /* Check if we have a valid impersonation level */ 787 if (SubjectContext.ImpersonationLevel < SecurityIdentification) 788 { 789 Status = STATUS_BAD_IMPERSONATION_LEVEL; 790 DPRINT1("Invalid impersonation level 0x%lx\n", 791 SubjectContext.ImpersonationLevel); 792 goto Cleanup; 793 } 794 } 795 796 /* Are we using a result list? */ 797 if (UseResultList) 798 { 799 /* The list length equals the object type list length */ 800 ResultListLength = ObjectTypeListLength; 801 if ((ResultListLength == 0) || (ResultListLength > 0x1000)) 802 { 803 Status = STATUS_INVALID_PARAMETER; 804 DPRINT1("Invalid ResultListLength: 0x%lx\n", ResultListLength); 805 goto Cleanup; 806 } 807 808 /* Allocate a safe buffer from paged pool */ 809 SafeGrantedAccessList = ExAllocatePoolWithTag(PagedPool, 810 2 * ResultListLength * sizeof(ULONG), 811 TAG_SEPA); 812 if (SafeGrantedAccessList == NULL) 813 { 814 Status = STATUS_INSUFFICIENT_RESOURCES; 815 DPRINT1("Failed to allocate access lists\n"); 816 goto Cleanup; 817 } 818 819 SafeAccessStatusList = (PNTSTATUS)&SafeGrantedAccessList[ResultListLength]; 820 AllocatedResultLists = TRUE; 821 } 822 else 823 { 824 /* List length is 1 */ 825 ResultListLength = 1; 826 SafeGrantedAccessList = &GrantedAccess; 827 SafeAccessStatusList = &AccessStatus; 828 } 829 830 _SEH2_TRY 831 { 832 /* Probe output buffers */ 833 ProbeForWrite(AccessStatusList, 834 ResultListLength * sizeof(*AccessStatusList), 835 sizeof(*AccessStatusList)); 836 ProbeForWrite(GrantedAccessList, 837 ResultListLength * sizeof(*GrantedAccessList), 838 sizeof(*GrantedAccessList)); 839 840 /* Probe generic mapping and make a local copy */ 841 ProbeForRead(GenericMapping, sizeof(*GenericMapping), sizeof(ULONG)); 842 LocalGenericMapping = * GenericMapping; 843 } 844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 845 { 846 Status = _SEH2_GetExceptionCode(); 847 DPRINT1("Exception while probing parameters: 0x%lx\n", Status); 848 _SEH2_YIELD(goto Cleanup); 849 } 850 _SEH2_END; 851 852 /* Do we have a client token? */ 853 if (ClientTokenHandle != NULL) 854 { 855 /* Reference the client token */ 856 Status = ObReferenceObjectByHandle(*ClientTokenHandle, 857 TOKEN_QUERY, 858 SeTokenObjectType, 859 UserMode, 860 (PVOID*)&ClientToken, 861 NULL); 862 if (!NT_SUCCESS(Status)) 863 { 864 DPRINT1("Failed to reference token handle %p: %lx\n", 865 *ClientTokenHandle, Status); 866 goto Cleanup; 867 } 868 869 SubjectContextToken = SubjectContext.ClientToken; 870 SubjectContext.ClientToken = ClientToken; 871 } 872 873 /* Check for audit privilege */ 874 HaveAuditPrivilege = SeCheckAuditPrivilege(&SubjectContext, UserMode); 875 if (!HaveAuditPrivilege && !(Flags & AUDIT_ALLOW_NO_PRIVILEGE)) 876 { 877 DPRINT1("Caller does not have SeAuditPrivilege\n"); 878 Status = STATUS_PRIVILEGE_NOT_HELD; 879 goto Cleanup; 880 } 881 882 /* Generic access must already be mapped to non-generic access types! */ 883 if (DesiredAccess & (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)) 884 { 885 DPRINT1("Generic access rights requested: 0x%lx\n", DesiredAccess); 886 Status = STATUS_GENERIC_NOT_MAPPED; 887 goto Cleanup; 888 } 889 890 /* Capture the security descriptor */ 891 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 892 UserMode, 893 PagedPool, 894 FALSE, 895 &CapturedSecurityDescriptor); 896 if (!NT_SUCCESS(Status)) 897 { 898 DPRINT1("Failed to capture security descriptor!\n"); 899 goto Cleanup; 900 } 901 902 /* Validate the Security descriptor */ 903 if ((SepGetOwnerFromDescriptor(CapturedSecurityDescriptor) == NULL) || 904 (SepGetGroupFromDescriptor(CapturedSecurityDescriptor) == NULL)) 905 { 906 Status = STATUS_INVALID_SECURITY_DESCR; 907 DPRINT1("Invalid security descriptor\n"); 908 goto Cleanup; 909 } 910 911 /* Probe and capture the subsystem name */ 912 Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName, 913 UserMode, 914 SubsystemName); 915 if (!NT_SUCCESS(Status)) 916 { 917 DPRINT1("Failed to capture subsystem name!\n"); 918 goto Cleanup; 919 } 920 921 /* Probe and capture the object type name */ 922 Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName, 923 UserMode, 924 ObjectTypeName); 925 if (!NT_SUCCESS(Status)) 926 { 927 DPRINT1("Failed to capture object type name!\n"); 928 goto Cleanup; 929 } 930 931 /* Probe and capture the object name */ 932 Status = ProbeAndCaptureUnicodeString(&CapturedObjectName, 933 UserMode, 934 ObjectName); 935 if (!NT_SUCCESS(Status)) 936 { 937 DPRINT1("Failed to capture object name!\n"); 938 goto Cleanup; 939 } 940 941 /* Check if we have a PrincipalSelfSid */ 942 if (PrincipalSelfSid != NULL) 943 { 944 /* Capture it */ 945 Status = SepCaptureSid(PrincipalSelfSid, 946 UserMode, 947 PagedPool, 948 FALSE, 949 &CapturedPrincipalSelfSid); 950 if (!NT_SUCCESS(Status)) 951 { 952 DPRINT1("Failed to capture PrincipalSelfSid!\n"); 953 goto Cleanup; 954 } 955 } 956 957 /* Capture the object type list */ 958 Status = SeCaptureObjectTypeList(ObjectTypeList, 959 ObjectTypeListLength, 960 UserMode, 961 &CapturedObjectTypeList); 962 if (!NT_SUCCESS(Status)) 963 { 964 DPRINT1("Failed to capture object type list!\n"); 965 goto Cleanup; 966 } 967 968 /* Call the worker routine with the captured buffers */ 969 Status = SepAccessCheckAndAuditAlarmWorker(&CapturedSubsystemName, 970 HandleId, 971 &SubjectContext, 972 &CapturedObjectTypeName, 973 &CapturedObjectName, 974 CapturedSecurityDescriptor, 975 CapturedPrincipalSelfSid, 976 DesiredAccess, 977 AuditType, 978 HaveAuditPrivilege, 979 CapturedObjectTypeList, 980 ObjectTypeListLength, 981 &LocalGenericMapping, 982 SafeGrantedAccessList, 983 SafeAccessStatusList, 984 &LocalGenerateOnClose, 985 UseResultList); 986 if (!NT_SUCCESS(Status)) 987 goto Cleanup; 988 989 /* Enter SEH to copy the data back to user mode */ 990 _SEH2_TRY 991 { 992 /* Loop all result entries (only 1 when no list was requested) */ 993 ASSERT(UseResultList || (ResultListLength == 1)); 994 for (i = 0; i < ResultListLength; i++) 995 { 996 AccessStatusList[i] = SafeAccessStatusList[i]; 997 GrantedAccessList[i] = SafeGrantedAccessList[i]; 998 } 999 1000 *GenerateOnClose = LocalGenerateOnClose; 1001 } 1002 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1003 { 1004 Status = _SEH2_GetExceptionCode(); 1005 DPRINT1("Exception while copying back data: 0x%lx\n", Status); 1006 } 1007 _SEH2_END; 1008 1009 Cleanup: 1010 1011 if (CapturedObjectTypeList != NULL) 1012 SeReleaseObjectTypeList(CapturedObjectTypeList, UserMode); 1013 1014 if (CapturedPrincipalSelfSid != NULL) 1015 SepReleaseSid(CapturedPrincipalSelfSid, UserMode, FALSE); 1016 1017 if (CapturedObjectName.Buffer != NULL) 1018 ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode); 1019 1020 if (CapturedObjectTypeName.Buffer != NULL) 1021 ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode); 1022 1023 if (CapturedSubsystemName.Buffer != NULL) 1024 ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode); 1025 1026 if (CapturedSecurityDescriptor != NULL) 1027 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE); 1028 1029 if (ClientToken != NULL) 1030 { 1031 ObDereferenceObject(ClientToken); 1032 SubjectContext.ClientToken = SubjectContextToken; 1033 } 1034 1035 if (AllocatedResultLists) 1036 ExFreePoolWithTag(SafeGrantedAccessList, TAG_SEPA); 1037 1038 /* Release the security subject context */ 1039 SeReleaseSubjectContext(&SubjectContext); 1040 1041 return Status; 1042 } 1043 1044 1045 /* PUBLIC FUNCTIONS ***********************************************************/ 1046 1047 /** 1048 * @unimplemented 1049 * @brief 1050 * Performs an audit against a hard link creation. 1051 * 1052 * @param[in] FileName 1053 * A Unicode string that points to the name of the file. 1054 * 1055 * @param[in] LinkName 1056 * A Unicode string that points to a link. 1057 * 1058 * @param[out] bSuccess 1059 * If TRUE, the function has successfully audited 1060 * the hard link and security access can be granted, 1061 * FALSE otherwise. 1062 * 1063 * @return 1064 * Nothing. 1065 */ 1066 VOID 1067 NTAPI 1068 SeAuditHardLinkCreation( 1069 _In_ PUNICODE_STRING FileName, 1070 _In_ PUNICODE_STRING LinkName, 1071 _In_ BOOLEAN bSuccess) 1072 { 1073 UNIMPLEMENTED; 1074 } 1075 1076 /** 1077 * @unimplemented 1078 * @brief 1079 * Determines whether auditing against file events is being 1080 * done or not. 1081 * 1082 * @param[in] AccessGranted 1083 * If set to TRUE, the access attempt is deemed as successful 1084 * otherwise set it to FALSE. 1085 * 1086 * @param[in] SecurityDescriptor 1087 * A security descriptor. 1088 * 1089 * @return 1090 * Returns TRUE if auditing is being currently done, FALSE otherwise. 1091 */ 1092 BOOLEAN 1093 NTAPI 1094 SeAuditingFileEvents( 1095 _In_ BOOLEAN AccessGranted, 1096 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor) 1097 { 1098 UNIMPLEMENTED; 1099 return FALSE; 1100 } 1101 1102 /** 1103 * @unimplemented 1104 * @brief 1105 * Determines whether auditing against file events with subject context 1106 * is being done or not. 1107 * 1108 * @param[in] AccessGranted 1109 * If set to TRUE, the access attempt is deemed as successful 1110 * otherwise set it to FALSE. 1111 * 1112 * @param[in] SecurityDescriptor 1113 * A security descriptor. 1114 * 1115 * @param[in] SubjectSecurityContext 1116 * If specified, the function will check if security auditing is currently 1117 * being done with this context. 1118 * 1119 * @return 1120 * Returns TRUE if auditing is being currently done, FALSE otherwise. 1121 */ 1122 BOOLEAN 1123 NTAPI 1124 SeAuditingFileEventsWithContext( 1125 _In_ BOOLEAN AccessGranted, 1126 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1127 _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext) 1128 { 1129 UNIMPLEMENTED_ONCE; 1130 return FALSE; 1131 } 1132 1133 /** 1134 * @unimplemented 1135 * @brief 1136 * Determines whether auditing against hard links events is being 1137 * done or not. 1138 * 1139 * @param[in] AccessGranted 1140 * If set to TRUE, the access attempt is deemed as successful 1141 * otherwise set it to FALSE. 1142 * 1143 * @param[in] SecurityDescriptor 1144 * A security descriptor. 1145 * 1146 * @return 1147 * Returns TRUE if auditing is being currently done, FALSE otherwise. 1148 */ 1149 BOOLEAN 1150 NTAPI 1151 SeAuditingHardLinkEvents( 1152 _In_ BOOLEAN AccessGranted, 1153 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor) 1154 { 1155 UNIMPLEMENTED; 1156 return FALSE; 1157 } 1158 1159 /** 1160 * @unimplemented 1161 * @brief 1162 * Determines whether auditing against hard links events with subject context 1163 * is being done or not. 1164 * 1165 * @param[in] AccessGranted 1166 * If set to TRUE, the access attempt is deemed as successful 1167 * otherwise set it to FALSE. 1168 * 1169 * @param[in] SecurityDescriptor 1170 * A security descriptor. 1171 * 1172 * @param[in] SubjectSecurityContext 1173 * If specified, the function will check if security auditing is currently 1174 * being done with this context. 1175 * 1176 * @return 1177 * Returns TRUE if auditing is being currently done, FALSE otherwise. 1178 */ 1179 BOOLEAN 1180 NTAPI 1181 SeAuditingHardLinkEventsWithContext( 1182 _In_ BOOLEAN AccessGranted, 1183 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1184 _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext) 1185 { 1186 UNIMPLEMENTED; 1187 return FALSE; 1188 } 1189 1190 /** 1191 * @unimplemented 1192 * @brief 1193 * Determines whether auditing against files or global events with 1194 * subject context is being done or not. 1195 * 1196 * @param[in] AccessGranted 1197 * If set to TRUE, the access attempt is deemed as successful 1198 * otherwise set it to FALSE. 1199 * 1200 * @param[in] SecurityDescriptor 1201 * A security descriptor. 1202 * 1203 * @param[in] SubjectSecurityContext 1204 * If specified, the function will check if security auditing is currently 1205 * being done with this context. 1206 * 1207 * @return 1208 * Returns TRUE if auditing is being currently done, FALSE otherwise. 1209 */ 1210 BOOLEAN 1211 NTAPI 1212 SeAuditingFileOrGlobalEvents( 1213 _In_ BOOLEAN AccessGranted, 1214 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1215 _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext) 1216 { 1217 UNIMPLEMENTED; 1218 return FALSE; 1219 } 1220 1221 /** 1222 * @unimplemented 1223 * @brief 1224 * Closes an alarm audit of an object. 1225 * 1226 * @param[in] Object 1227 * An arbitrary pointer data that points to the object. 1228 * 1229 * @param[in] Handle 1230 * A handle of the said object. 1231 * 1232 * @param[in] PerformAction 1233 * Set this to TRUE to perform any auxiliary action, otherwise 1234 * set to FALSE. 1235 * 1236 * @return 1237 * Nothing. 1238 */ 1239 VOID 1240 NTAPI 1241 SeCloseObjectAuditAlarm( 1242 _In_ PVOID Object, 1243 _In_ HANDLE Handle, 1244 _In_ BOOLEAN PerformAction) 1245 { 1246 UNIMPLEMENTED; 1247 } 1248 1249 /** 1250 * @unimplemented 1251 * @brief 1252 * Deletes an alarm audit of an object. 1253 * 1254 * @param[in] Object 1255 * An arbitrary pointer data that points to the object. 1256 * 1257 * @param[in] Handle 1258 * A handle of the said object. 1259 * 1260 * @return 1261 * Nothing. 1262 */ 1263 VOID NTAPI 1264 SeDeleteObjectAuditAlarm( 1265 _In_ PVOID Object, 1266 _In_ HANDLE Handle) 1267 { 1268 UNIMPLEMENTED; 1269 } 1270 1271 /** 1272 * @unimplemented 1273 * @brief 1274 * Creates an audit with alarm notification of an object 1275 * that is being opened. 1276 * 1277 * @param[in] ObjectTypeName 1278 * A Unicode string that points to the object type name. 1279 * 1280 * @param[in] Object 1281 * If specified, the function will use this parameter to 1282 * directly open the object. 1283 * 1284 * @param[in] AbsoluteObjectName 1285 * If specified, the function will use this parameter to 1286 * directly open the object through the absolute name 1287 * of the object. 1288 * 1289 * @param[in] SecurityDescriptor 1290 * A security descriptor. 1291 * 1292 * @param[in] AccessState 1293 * An access state right mask when opening the object. 1294 * 1295 * @param[in] ObjectCreated 1296 * Set this to TRUE if the object has been fully created, 1297 * FALSE otherwise. 1298 * 1299 * @param[in] AccessGranted 1300 * Set this to TRUE if access was deemed as granted. 1301 * 1302 * @param[in] AccessMode 1303 * Processor level access mode. 1304 * 1305 * @param[out] GenerateOnClose 1306 * A boolean flag returned to the caller once audit generation procedure 1307 * finishes. 1308 * 1309 * @return 1310 * Nothing. 1311 */ 1312 VOID 1313 NTAPI 1314 SeOpenObjectAuditAlarm( 1315 _In_ PUNICODE_STRING ObjectTypeName, 1316 _In_opt_ PVOID Object, 1317 _In_opt_ PUNICODE_STRING AbsoluteObjectName, 1318 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1319 _In_ PACCESS_STATE AccessState, 1320 _In_ BOOLEAN ObjectCreated, 1321 _In_ BOOLEAN AccessGranted, 1322 _In_ KPROCESSOR_MODE AccessMode, 1323 _Out_ PBOOLEAN GenerateOnClose) 1324 { 1325 PAGED_CODE(); 1326 1327 /* Audits aren't done on kernel-mode access */ 1328 if (AccessMode == KernelMode) return; 1329 1330 /* Otherwise, unimplemented! */ 1331 //UNIMPLEMENTED; 1332 return; 1333 } 1334 1335 /** 1336 * @unimplemented 1337 * @brief 1338 * Creates an audit with alarm notification of an object 1339 * that is being opened for deletion. 1340 * 1341 * @param[in] ObjectTypeName 1342 * A Unicode string that points to the object type name. 1343 * 1344 * @param[in] Object 1345 * If specified, the function will use this parameter to 1346 * directly open the object. 1347 * 1348 * @param[in] AbsoluteObjectName 1349 * If specified, the function will use this parameter to 1350 * directly open the object through the absolute name 1351 * of the object. 1352 * 1353 * @param[in] SecurityDescriptor 1354 * A security descriptor. 1355 * 1356 * @param[in] AccessState 1357 * An access state right mask when opening the object. 1358 * 1359 * @param[in] ObjectCreated 1360 * Set this to TRUE if the object has been fully created, 1361 * FALSE otherwise. 1362 * 1363 * @param[in] AccessGranted 1364 * Set this to TRUE if access was deemed as granted. 1365 * 1366 * @param[in] AccessMode 1367 * Processor level access mode. 1368 * 1369 * @param[out] GenerateOnClose 1370 * A boolean flag returned to the caller once audit generation procedure 1371 * finishes. 1372 * 1373 * @return 1374 * Nothing. 1375 */ 1376 VOID NTAPI 1377 SeOpenObjectForDeleteAuditAlarm( 1378 _In_ PUNICODE_STRING ObjectTypeName, 1379 _In_opt_ PVOID Object, 1380 _In_opt_ PUNICODE_STRING AbsoluteObjectName, 1381 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1382 _In_ PACCESS_STATE AccessState, 1383 _In_ BOOLEAN ObjectCreated, 1384 _In_ BOOLEAN AccessGranted, 1385 _In_ KPROCESSOR_MODE AccessMode, 1386 _Out_ PBOOLEAN GenerateOnClose) 1387 { 1388 UNIMPLEMENTED; 1389 } 1390 1391 /** 1392 * @unimplemented 1393 * @brief 1394 * Raises an audit with alarm notification message 1395 * when an object tries to acquire this privilege. 1396 * 1397 * @param[in] Handle 1398 * A handle to an object. 1399 * 1400 * @param[in] SubjectContext 1401 * The security subject context for auditing. 1402 * 1403 * @param[in] DesiredAccess 1404 * The desired right access masks requested by the caller. 1405 * 1406 * @param[in] Privileges 1407 * An array set of privileges for auditing. 1408 * 1409 * @param[out] AccessGranted 1410 * When the auditing procedure routine ends, it returns TRUE to the 1411 * caller if the object has the required privileges for access, 1412 * FALSE otherwise. 1413 * 1414 * @param[in] CurrentMode 1415 * Processor level access mode. 1416 * 1417 * @return 1418 * Nothing. 1419 */ 1420 VOID 1421 NTAPI 1422 SePrivilegeObjectAuditAlarm( 1423 _In_ HANDLE Handle, 1424 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 1425 _In_ ACCESS_MASK DesiredAccess, 1426 _In_ PPRIVILEGE_SET Privileges, 1427 _In_ BOOLEAN AccessGranted, 1428 _In_ KPROCESSOR_MODE CurrentMode) 1429 { 1430 UNIMPLEMENTED; 1431 } 1432 1433 /* SYSTEM CALLS ***************************************************************/ 1434 1435 /** 1436 * @brief 1437 * Raises an alarm audit message when an object is about 1438 * to be closed. 1439 * 1440 * @param[in] SubsystemName 1441 * A Unicode string that points to the name of the subsystem. 1442 * 1443 * @param[in] HandleId 1444 * A handle of an ID used for identification instance for auditing. 1445 * 1446 * @param[in] GenerateOnClose 1447 * A boolean value previously created by the "open" equivalent of this 1448 * function. If the caller explicitly sets this to FALSE, the function 1449 * assumes that the object is not opened. 1450 * 1451 * @return 1452 * Returns STATUS_SUCCESS if all the operations have completed successfully. 1453 * STATUS_PRIVILEGE_NOT_HELD is returned if the security subject context 1454 * does not have the audit privilege to actually begin auditing procedures 1455 * in the first place. 1456 */ 1457 NTSTATUS 1458 NTAPI 1459 NtCloseObjectAuditAlarm( 1460 _In_ PUNICODE_STRING SubsystemName, 1461 _In_ PVOID HandleId, 1462 _In_ BOOLEAN GenerateOnClose) 1463 { 1464 SECURITY_SUBJECT_CONTEXT SubjectContext; 1465 UNICODE_STRING CapturedSubsystemName; 1466 KPROCESSOR_MODE PreviousMode; 1467 BOOLEAN UseImpersonationToken; 1468 PETHREAD CurrentThread; 1469 BOOLEAN CopyOnOpen, EffectiveOnly; 1470 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 1471 NTSTATUS Status; 1472 PTOKEN Token; 1473 PAGED_CODE(); 1474 1475 /* Get the previous mode (only user mode is supported!) */ 1476 PreviousMode = ExGetPreviousMode(); 1477 ASSERT(PreviousMode != KernelMode); 1478 1479 /* Do we even need to do anything? */ 1480 if (!GenerateOnClose) 1481 { 1482 /* Nothing to do, return success */ 1483 return STATUS_SUCCESS; 1484 } 1485 1486 /* Capture the security subject context */ 1487 SeCaptureSubjectContext(&SubjectContext); 1488 1489 /* Check for audit privilege */ 1490 if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode)) 1491 { 1492 DPRINT1("Caller does not have SeAuditPrivilege\n"); 1493 Status = STATUS_PRIVILEGE_NOT_HELD; 1494 goto Cleanup; 1495 } 1496 1497 /* Probe and capture the subsystem name */ 1498 Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName, 1499 PreviousMode, 1500 SubsystemName); 1501 if (!NT_SUCCESS(Status)) 1502 { 1503 DPRINT1("Failed to capture subsystem name!\n"); 1504 goto Cleanup; 1505 } 1506 1507 /* Get the current thread and check if it's impersonating */ 1508 CurrentThread = PsGetCurrentThread(); 1509 if (PsIsThreadImpersonating(CurrentThread)) 1510 { 1511 /* Get the impersonation token */ 1512 Token = PsReferenceImpersonationToken(CurrentThread, 1513 &CopyOnOpen, 1514 &EffectiveOnly, 1515 &ImpersonationLevel); 1516 UseImpersonationToken = TRUE; 1517 } 1518 else 1519 { 1520 /* Get the primary token */ 1521 Token = PsReferencePrimaryToken(PsGetCurrentProcess()); 1522 UseImpersonationToken = FALSE; 1523 } 1524 1525 /* Call the internal function */ 1526 SepAdtCloseObjectAuditAlarm(&CapturedSubsystemName, 1527 HandleId, 1528 Token->UserAndGroups->Sid); 1529 1530 /* Release the captured subsystem name */ 1531 ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode); 1532 1533 /* Check what token we used */ 1534 if (UseImpersonationToken) 1535 { 1536 /* Release impersonation token */ 1537 PsDereferenceImpersonationToken(Token); 1538 } 1539 else 1540 { 1541 /* Release primary token */ 1542 PsDereferencePrimaryToken(Token); 1543 } 1544 1545 Status = STATUS_SUCCESS; 1546 1547 Cleanup: 1548 1549 /* Release the security subject context */ 1550 SeReleaseSubjectContext(&SubjectContext); 1551 1552 return Status; 1553 } 1554 1555 /** 1556 * @unimplemented 1557 * @brief 1558 * Raises an alarm audit message when an object is about 1559 * to be deleted. 1560 * 1561 * @param[in] SubsystemName 1562 * A Unicode string that points to the name of the subsystem. 1563 * 1564 * @param[in] HandleId 1565 * A handle of an ID used for identification instance for auditing. 1566 * 1567 * @param[in] GenerateOnClose 1568 * A boolean value previously created by the "open" equivalent of this 1569 * function. If the caller explicitly sets this to FALSE, the function 1570 * assumes that the object is not opened. 1571 * 1572 * @return 1573 * To be added... 1574 */ 1575 NTSTATUS NTAPI 1576 NtDeleteObjectAuditAlarm( 1577 _In_ PUNICODE_STRING SubsystemName, 1578 _In_ PVOID HandleId, 1579 _In_ BOOLEAN GenerateOnClose) 1580 { 1581 UNIMPLEMENTED; 1582 return STATUS_NOT_IMPLEMENTED; 1583 } 1584 1585 /** 1586 * @unimplemented 1587 * @brief 1588 * Raises an alarm audit message when an object is about 1589 * to be opened. 1590 * 1591 * @param[in] SubjectContext 1592 * A security subject context for auditing. 1593 * 1594 * @param[in] SubsystemName 1595 * A Unicode string that points to a name of the subsystem. 1596 * 1597 * @param[in] HandleId 1598 * A handle to an ID used for identification instance for auditing. 1599 * 1600 * @param[in] ObjectTypeName 1601 * A Unicode string that points to an object type name. 1602 * 1603 * @param[in] ObjectName 1604 * The name of the object. 1605 * 1606 * @param[in] SecurityDescriptor 1607 * A security descriptor. 1608 * 1609 * @param[in] ClientToken 1610 * A client access token, representing the client we want to impersonate. 1611 * 1612 * @param[in] DesiredAccess 1613 * The desired access rights masks requested by the caller. 1614 * 1615 * @param[in] GrantedAccess 1616 * The granted access mask rights. 1617 * 1618 * @param[in] Privileges 1619 * If specified, the function will use this set of privileges to audit. 1620 * 1621 * @param[in] ObjectCreation 1622 * Set this to TRUE if the object has just been created. 1623 * 1624 * @param[in] AccessGranted 1625 * Set this to TRUE if the access attempt was deemed as granted. 1626 * 1627 * @param[out] GenerateOnClose 1628 * A boolean flag returned to the caller once audit generation procedure 1629 * finishes. 1630 * 1631 * @return 1632 * Nothing. 1633 */ 1634 VOID 1635 NTAPI 1636 SepOpenObjectAuditAlarm( 1637 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 1638 _In_ PUNICODE_STRING SubsystemName, 1639 _In_opt_ PVOID HandleId, 1640 _In_ PUNICODE_STRING ObjectTypeName, 1641 _In_ PUNICODE_STRING ObjectName, 1642 _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1643 _In_ PTOKEN ClientToken, 1644 _In_ ACCESS_MASK DesiredAccess, 1645 _In_ ACCESS_MASK GrantedAccess, 1646 _In_opt_ PPRIVILEGE_SET Privileges, 1647 _In_ BOOLEAN ObjectCreation, 1648 _In_ BOOLEAN AccessGranted, 1649 _Out_ PBOOLEAN GenerateOnClose) 1650 { 1651 DBG_UNREFERENCED_PARAMETER(SubjectContext); 1652 DBG_UNREFERENCED_PARAMETER(SubsystemName); 1653 DBG_UNREFERENCED_PARAMETER(HandleId); 1654 DBG_UNREFERENCED_PARAMETER(ObjectTypeName); 1655 DBG_UNREFERENCED_PARAMETER(ObjectName); 1656 DBG_UNREFERENCED_PARAMETER(SecurityDescriptor); 1657 DBG_UNREFERENCED_PARAMETER(ClientToken); 1658 DBG_UNREFERENCED_PARAMETER(DesiredAccess); 1659 DBG_UNREFERENCED_PARAMETER(GrantedAccess); 1660 DBG_UNREFERENCED_PARAMETER(Privileges); 1661 DBG_UNREFERENCED_PARAMETER(ObjectCreation); 1662 DBG_UNREFERENCED_PARAMETER(AccessGranted); 1663 UNIMPLEMENTED; 1664 *GenerateOnClose = FALSE; 1665 } 1666 1667 /** 1668 * @brief 1669 * Raises an alarm audit message when an object is about 1670 * to be opened. 1671 * 1672 * @param[in] SubsystemName 1673 * A Unicode string that points to a name of the subsystem. 1674 * 1675 * @param[in] HandleId 1676 * A handle to an ID used for identification instance for auditing. 1677 * 1678 * @param[in] ObjectTypeName 1679 * A Unicode string that points to an object type name. 1680 * 1681 * @param[in] ObjectName 1682 * The name of the object. 1683 * 1684 * @param[in] SecurityDescriptor 1685 * A security descriptor. 1686 * 1687 * @param[in] ClientTokenHandle 1688 * A handle to a client access token. 1689 * 1690 * @param[in] DesiredAccess 1691 * The desired access rights masks requested by the caller. 1692 * 1693 * @param[in] GrantedAccess 1694 * The granted access mask rights. 1695 * 1696 * @param[in] PrivilegeSet 1697 * If specified, the function will use this set of privileges to audit. 1698 * 1699 * @param[in] ObjectCreation 1700 * Set this to TRUE if the object has just been created. 1701 * 1702 * @param[in] AccessGranted 1703 * Set this to TRUE if the access attempt was deemed as granted. 1704 * 1705 * @param[out] GenerateOnClose 1706 * A boolean flag returned to the caller once audit generation procedure 1707 * finishes. 1708 * 1709 * @return 1710 * Returns STATUS_SUCCESS if all the operations have been completed successfully. 1711 * STATUS_PRIVILEGE_NOT_HELD is returned if the given subject context does not 1712 * hold the required audit privilege to actually begin auditing in the first place. 1713 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the security impersonation level 1714 * of the client token is not on par with the impersonation level that alllows 1715 * impersonation. STATUS_INVALID_PARAMETER is returned if the caller has 1716 * submitted a bogus set of privileges as such array set exceeds the maximum 1717 * count of privileges that the kernel can accept. A failure NTSTATUS code 1718 * is returned otherwise. 1719 */ 1720 __kernel_entry 1721 NTSTATUS 1722 NTAPI 1723 NtOpenObjectAuditAlarm( 1724 _In_ PUNICODE_STRING SubsystemName, 1725 _In_opt_ PVOID HandleId, 1726 _In_ PUNICODE_STRING ObjectTypeName, 1727 _In_ PUNICODE_STRING ObjectName, 1728 _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor, 1729 _In_ HANDLE ClientTokenHandle, 1730 _In_ ACCESS_MASK DesiredAccess, 1731 _In_ ACCESS_MASK GrantedAccess, 1732 _In_opt_ PPRIVILEGE_SET PrivilegeSet, 1733 _In_ BOOLEAN ObjectCreation, 1734 _In_ BOOLEAN AccessGranted, 1735 _Out_ PBOOLEAN GenerateOnClose) 1736 { 1737 PTOKEN ClientToken; 1738 PSECURITY_DESCRIPTOR CapturedSecurityDescriptor; 1739 UNICODE_STRING CapturedSubsystemName, CapturedObjectTypeName, CapturedObjectName; 1740 ULONG PrivilegeCount, PrivilegeSetSize; 1741 volatile PPRIVILEGE_SET CapturedPrivilegeSet; 1742 BOOLEAN LocalGenerateOnClose; 1743 PVOID CapturedHandleId; 1744 SECURITY_SUBJECT_CONTEXT SubjectContext; 1745 NTSTATUS Status; 1746 PAGED_CODE(); 1747 1748 /* Only user mode is supported! */ 1749 ASSERT(ExGetPreviousMode() != KernelMode); 1750 1751 /* Start clean */ 1752 ClientToken = NULL; 1753 CapturedSecurityDescriptor = NULL; 1754 CapturedPrivilegeSet = NULL; 1755 CapturedSubsystemName.Buffer = NULL; 1756 CapturedObjectTypeName.Buffer = NULL; 1757 CapturedObjectName.Buffer = NULL; 1758 1759 /* Reference the client token */ 1760 Status = ObReferenceObjectByHandle(ClientTokenHandle, 1761 TOKEN_QUERY, 1762 SeTokenObjectType, 1763 UserMode, 1764 (PVOID*)&ClientToken, 1765 NULL); 1766 if (!NT_SUCCESS(Status)) 1767 { 1768 DPRINT1("Failed to reference token handle %p: %lx\n", 1769 ClientTokenHandle, Status); 1770 return Status; 1771 } 1772 1773 /* Capture the security subject context */ 1774 SeCaptureSubjectContext(&SubjectContext); 1775 1776 /* Validate the token's impersonation level */ 1777 if ((ClientToken->TokenType == TokenImpersonation) && 1778 (ClientToken->ImpersonationLevel < SecurityIdentification)) 1779 { 1780 DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel); 1781 Status = STATUS_BAD_IMPERSONATION_LEVEL; 1782 goto Cleanup; 1783 } 1784 1785 /* Check for audit privilege */ 1786 if (!SeCheckAuditPrivilege(&SubjectContext, UserMode)) 1787 { 1788 DPRINT1("Caller does not have SeAuditPrivilege\n"); 1789 Status = STATUS_PRIVILEGE_NOT_HELD; 1790 goto Cleanup; 1791 } 1792 1793 /* Check for NULL SecurityDescriptor */ 1794 if (SecurityDescriptor == NULL) 1795 { 1796 /* Nothing to do */ 1797 Status = STATUS_SUCCESS; 1798 goto Cleanup; 1799 } 1800 1801 /* Capture the security descriptor */ 1802 Status = SeCaptureSecurityDescriptor(SecurityDescriptor, 1803 UserMode, 1804 PagedPool, 1805 FALSE, 1806 &CapturedSecurityDescriptor); 1807 if (!NT_SUCCESS(Status)) 1808 { 1809 DPRINT1("Failed to capture security descriptor!\n"); 1810 goto Cleanup; 1811 } 1812 1813 _SEH2_TRY 1814 { 1815 /* Check if we have a privilege set */ 1816 if (PrivilegeSet != NULL) 1817 { 1818 /* Probe the basic privilege set structure */ 1819 ProbeForRead(PrivilegeSet, sizeof(PRIVILEGE_SET), sizeof(ULONG)); 1820 1821 /* Validate privilege count */ 1822 PrivilegeCount = PrivilegeSet->PrivilegeCount; 1823 if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT) 1824 { 1825 Status = STATUS_INVALID_PARAMETER; 1826 _SEH2_YIELD(goto Cleanup); 1827 } 1828 1829 /* Calculate the size of the PrivilegeSet structure */ 1830 PrivilegeSetSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]); 1831 1832 /* Probe the whole structure */ 1833 ProbeForRead(PrivilegeSet, PrivilegeSetSize, sizeof(ULONG)); 1834 1835 /* Allocate a temp buffer */ 1836 CapturedPrivilegeSet = ExAllocatePoolWithTag(PagedPool, 1837 PrivilegeSetSize, 1838 TAG_PRIVILEGE_SET); 1839 if (CapturedPrivilegeSet == NULL) 1840 { 1841 DPRINT1("Failed to allocate %u bytes\n", PrivilegeSetSize); 1842 Status = STATUS_INSUFFICIENT_RESOURCES; 1843 _SEH2_YIELD(goto Cleanup); 1844 } 1845 1846 /* Copy the privileges */ 1847 RtlCopyMemory(CapturedPrivilegeSet, PrivilegeSet, PrivilegeSetSize); 1848 } 1849 1850 if (HandleId != NULL) 1851 { 1852 ProbeForRead(HandleId, sizeof(PVOID), sizeof(PVOID)); 1853 CapturedHandleId = *(PVOID*)HandleId; 1854 } 1855 1856 ProbeForWrite(GenerateOnClose, sizeof(BOOLEAN), sizeof(BOOLEAN)); 1857 } 1858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1859 { 1860 Status = _SEH2_GetExceptionCode(); 1861 DPRINT1("Exception while probing parameters: 0x%lx\n", Status); 1862 _SEH2_YIELD(goto Cleanup); 1863 } 1864 _SEH2_END; 1865 1866 /* Probe and capture the subsystem name */ 1867 Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName, 1868 UserMode, 1869 SubsystemName); 1870 if (!NT_SUCCESS(Status)) 1871 { 1872 DPRINT1("Failed to capture subsystem name!\n"); 1873 goto Cleanup; 1874 } 1875 1876 /* Probe and capture the object type name */ 1877 Status = ProbeAndCaptureUnicodeString(&CapturedObjectTypeName, 1878 UserMode, 1879 ObjectTypeName); 1880 if (!NT_SUCCESS(Status)) 1881 { 1882 DPRINT1("Failed to capture object type name!\n"); 1883 goto Cleanup; 1884 } 1885 1886 /* Probe and capture the object name */ 1887 Status = ProbeAndCaptureUnicodeString(&CapturedObjectName, 1888 UserMode, 1889 ObjectName); 1890 if (!NT_SUCCESS(Status)) 1891 { 1892 DPRINT1("Failed to capture object name!\n"); 1893 goto Cleanup; 1894 } 1895 1896 /* Call the internal function */ 1897 SepOpenObjectAuditAlarm(&SubjectContext, 1898 &CapturedSubsystemName, 1899 CapturedHandleId, 1900 &CapturedObjectTypeName, 1901 &CapturedObjectName, 1902 CapturedSecurityDescriptor, 1903 ClientToken, 1904 DesiredAccess, 1905 GrantedAccess, 1906 CapturedPrivilegeSet, 1907 ObjectCreation, 1908 AccessGranted, 1909 &LocalGenerateOnClose); 1910 1911 Status = STATUS_SUCCESS; 1912 1913 /* Enter SEH to copy the data back to user mode */ 1914 _SEH2_TRY 1915 { 1916 *GenerateOnClose = LocalGenerateOnClose; 1917 } 1918 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1919 { 1920 Status = _SEH2_GetExceptionCode(); 1921 DPRINT1("Exception while copying back data: 0x%lx\n", Status); 1922 } 1923 _SEH2_END; 1924 1925 Cleanup: 1926 1927 if (CapturedObjectName.Buffer != NULL) 1928 ReleaseCapturedUnicodeString(&CapturedObjectName, UserMode); 1929 1930 if (CapturedObjectTypeName.Buffer != NULL) 1931 ReleaseCapturedUnicodeString(&CapturedObjectTypeName, UserMode); 1932 1933 if (CapturedSubsystemName.Buffer != NULL) 1934 ReleaseCapturedUnicodeString(&CapturedSubsystemName, UserMode); 1935 1936 if (CapturedSecurityDescriptor != NULL) 1937 SeReleaseSecurityDescriptor(CapturedSecurityDescriptor, UserMode, FALSE); 1938 1939 if (CapturedPrivilegeSet != NULL) 1940 ExFreePoolWithTag(CapturedPrivilegeSet, TAG_PRIVILEGE_SET); 1941 1942 /* Release the security subject context */ 1943 SeReleaseSubjectContext(&SubjectContext); 1944 1945 ObDereferenceObject(ClientToken); 1946 1947 return Status; 1948 } 1949 1950 /** 1951 * @brief 1952 * Raises an alarm audit message when a caller attempts to request 1953 * a privileged service call. 1954 * 1955 * @param[in] SubsystemName 1956 * A Unicode string that points to a name of the subsystem. 1957 * 1958 * @param[in] ServiceName 1959 * A Unicode string that points to a name of the privileged service. 1960 * 1961 * @param[in] ClientTokenHandle 1962 * A handle to a client access token. 1963 * 1964 * @param[in] Privileges 1965 * An array set of privileges. 1966 * 1967 * @param[in] AccessGranted 1968 * Set this to TRUE if the access attempt was deemed as granted. 1969 * 1970 * @return 1971 * Returns STATUS_SUCCESS if all the operations have been completed successfully. 1972 * STATUS_PRIVILEGE_NOT_HELD is returned if the given subject context does not 1973 * hold the required audit privilege to actually begin auditing in the first place. 1974 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the security impersonation level 1975 * of the client token is not on par with the impersonation level that alllows 1976 * impersonation. STATUS_INVALID_PARAMETER is returned if the caller has 1977 * submitted a bogus set of privileges as such array set exceeds the maximum 1978 * count of privileges that the kernel can accept. A failure NTSTATUS code 1979 * is returned otherwise. 1980 */ 1981 __kernel_entry 1982 NTSTATUS 1983 NTAPI 1984 NtPrivilegedServiceAuditAlarm( 1985 _In_opt_ PUNICODE_STRING SubsystemName, 1986 _In_opt_ PUNICODE_STRING ServiceName, 1987 _In_ HANDLE ClientTokenHandle, 1988 _In_ PPRIVILEGE_SET Privileges, 1989 _In_ BOOLEAN AccessGranted) 1990 { 1991 KPROCESSOR_MODE PreviousMode; 1992 PTOKEN ClientToken; 1993 volatile PPRIVILEGE_SET CapturedPrivileges = NULL; 1994 UNICODE_STRING CapturedSubsystemName; 1995 UNICODE_STRING CapturedServiceName; 1996 ULONG PrivilegeCount, PrivilegesSize; 1997 SECURITY_SUBJECT_CONTEXT SubjectContext; 1998 NTSTATUS Status; 1999 PAGED_CODE(); 2000 2001 /* Get the previous mode (only user mode is supported!) */ 2002 PreviousMode = ExGetPreviousMode(); 2003 ASSERT(PreviousMode != KernelMode); 2004 2005 CapturedSubsystemName.Buffer = NULL; 2006 CapturedServiceName.Buffer = NULL; 2007 2008 /* Reference the client token */ 2009 Status = ObReferenceObjectByHandle(ClientTokenHandle, 2010 TOKEN_QUERY, 2011 SeTokenObjectType, 2012 PreviousMode, 2013 (PVOID*)&ClientToken, 2014 NULL); 2015 if (!NT_SUCCESS(Status)) 2016 { 2017 DPRINT1("Failed to reference client token: 0x%lx\n", Status); 2018 return Status; 2019 } 2020 2021 /* Validate the token's impersonation level */ 2022 if ((ClientToken->TokenType == TokenImpersonation) && 2023 (ClientToken->ImpersonationLevel < SecurityIdentification)) 2024 { 2025 DPRINT1("Invalid impersonation level (%u)\n", ClientToken->ImpersonationLevel); 2026 ObDereferenceObject(ClientToken); 2027 return STATUS_BAD_IMPERSONATION_LEVEL; 2028 } 2029 2030 /* Capture the security subject context */ 2031 SeCaptureSubjectContext(&SubjectContext); 2032 2033 /* Check for audit privilege */ 2034 if (!SeCheckAuditPrivilege(&SubjectContext, PreviousMode)) 2035 { 2036 DPRINT1("Caller does not have SeAuditPrivilege\n"); 2037 Status = STATUS_PRIVILEGE_NOT_HELD; 2038 goto Cleanup; 2039 } 2040 2041 /* Do we have a subsystem name? */ 2042 if (SubsystemName != NULL) 2043 { 2044 /* Probe and capture the subsystem name */ 2045 Status = ProbeAndCaptureUnicodeString(&CapturedSubsystemName, 2046 PreviousMode, 2047 SubsystemName); 2048 if (!NT_SUCCESS(Status)) 2049 { 2050 DPRINT1("Failed to capture subsystem name!\n"); 2051 goto Cleanup; 2052 } 2053 } 2054 2055 /* Do we have a service name? */ 2056 if (ServiceName != NULL) 2057 { 2058 /* Probe and capture the service name */ 2059 Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, 2060 PreviousMode, 2061 ServiceName); 2062 if (!NT_SUCCESS(Status)) 2063 { 2064 DPRINT1("Failed to capture service name!\n"); 2065 goto Cleanup; 2066 } 2067 } 2068 2069 _SEH2_TRY 2070 { 2071 /* Probe the basic privilege set structure */ 2072 ProbeForRead(Privileges, sizeof(PRIVILEGE_SET), sizeof(ULONG)); 2073 2074 /* Validate privilege count */ 2075 PrivilegeCount = Privileges->PrivilegeCount; 2076 if (PrivilegeCount > SEP_PRIVILEGE_SET_MAX_COUNT) 2077 { 2078 Status = STATUS_INVALID_PARAMETER; 2079 _SEH2_YIELD(goto Cleanup); 2080 } 2081 2082 /* Calculate the size of the Privileges structure */ 2083 PrivilegesSize = FIELD_OFFSET(PRIVILEGE_SET, Privilege[PrivilegeCount]); 2084 2085 /* Probe the whole structure */ 2086 ProbeForRead(Privileges, PrivilegesSize, sizeof(ULONG)); 2087 2088 /* Allocate a temp buffer */ 2089 CapturedPrivileges = ExAllocatePoolWithTag(PagedPool, 2090 PrivilegesSize, 2091 TAG_PRIVILEGE_SET); 2092 if (CapturedPrivileges == NULL) 2093 { 2094 DPRINT1("Failed to allocate %u bytes\n", PrivilegesSize); 2095 Status = STATUS_INSUFFICIENT_RESOURCES; 2096 _SEH2_YIELD(goto Cleanup); 2097 } 2098 2099 /* Copy the privileges */ 2100 RtlCopyMemory(CapturedPrivileges, Privileges, PrivilegesSize); 2101 } 2102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2103 { 2104 Status = _SEH2_GetExceptionCode(); 2105 DPRINT1("Got exception 0x%lx\n", Status); 2106 _SEH2_YIELD(goto Cleanup); 2107 } 2108 _SEH2_END; 2109 2110 /* Call the internal function */ 2111 SepAdtPrivilegedServiceAuditAlarm(&SubjectContext, 2112 SubsystemName ? &CapturedSubsystemName : NULL, 2113 ServiceName ? &CapturedServiceName : NULL, 2114 ClientToken, 2115 SubjectContext.PrimaryToken, 2116 CapturedPrivileges, 2117 AccessGranted); 2118 2119 Status = STATUS_SUCCESS; 2120 2121 Cleanup: 2122 /* Cleanup resources */ 2123 if (CapturedSubsystemName.Buffer != NULL) 2124 ReleaseCapturedUnicodeString(&CapturedSubsystemName, PreviousMode); 2125 2126 if (CapturedServiceName.Buffer != NULL) 2127 ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode); 2128 2129 if (CapturedPrivileges != NULL) 2130 ExFreePoolWithTag(CapturedPrivileges, TAG_PRIVILEGE_SET); 2131 2132 /* Release the security subject context */ 2133 SeReleaseSubjectContext(&SubjectContext); 2134 2135 ObDereferenceObject(ClientToken); 2136 2137 return Status; 2138 } 2139 2140 /** 2141 * @brief 2142 * Raises an alarm audit message when a caller attempts to access a 2143 * privileged object. 2144 * 2145 * @param[in] SubsystemName 2146 * A Unicode string that points to a name of the subsystem. 2147 * 2148 * @param[in] HandleId 2149 * A handle to an ID that is used as identification instance for auditing. 2150 * 2151 * @param[in] ClientToken 2152 * A handle to a client access token. 2153 * 2154 * @param[in] DesiredAccess 2155 * A handle to a client access token. 2156 * 2157 * @param[in] Privileges 2158 * An array set of privileges. 2159 * 2160 * @param[in] AccessGranted 2161 * Set this to TRUE if the access attempt was deemed as granted. 2162 * 2163 * @return 2164 * To be added... 2165 */ 2166 NTSTATUS NTAPI 2167 NtPrivilegeObjectAuditAlarm( 2168 _In_ PUNICODE_STRING SubsystemName, 2169 _In_ PVOID HandleId, 2170 _In_ HANDLE ClientToken, 2171 _In_ ULONG DesiredAccess, 2172 _In_ PPRIVILEGE_SET Privileges, 2173 _In_ BOOLEAN AccessGranted) 2174 { 2175 UNIMPLEMENTED; 2176 return STATUS_NOT_IMPLEMENTED; 2177 } 2178 2179 /** 2180 * @brief 2181 * Raises an alarm audit message when a caller attempts to access an 2182 * object and determine if the access can be made. 2183 * 2184 * @param[in] SubsystemName 2185 * A Unicode string that points to a name of the subsystem. 2186 * 2187 * @param[in] HandleId 2188 * A handle to an ID that is used as identification instance for auditing. 2189 * 2190 * @param[in] ObjectTypeName 2191 * The name of the object type. 2192 * 2193 * @param[in] ObjectName 2194 * The object name. 2195 * 2196 * @param[in] SecurityDescriptor 2197 * A security descriptor. 2198 * 2199 * @param[in] DesiredAccess 2200 * The desired access rights masks requested by the caller. 2201 * 2202 * @param[in] GenericMapping 2203 * The generic mapping of access mask rights. 2204 * 2205 * @param[in] ObjectCreation 2206 * Set this to TRUE if the object has just been created. 2207 * 2208 * @param[out] GrantedAccess 2209 * Returns the granted access rights. 2210 * 2211 * @param[out] AccessStatus 2212 * Returns a NTSTATUS status code indicating whether access check 2213 * can be granted or not. 2214 * 2215 * @param[out] GenerateOnClose 2216 * Returns TRUE if the function has generated a list of granted access rights and 2217 * status codes on termination, FALSE otherwise. 2218 * 2219 * @return 2220 * See SepAccessCheckAndAuditAlarm. 2221 */ 2222 _Must_inspect_result_ 2223 __kernel_entry 2224 NTSTATUS 2225 NTAPI 2226 NtAccessCheckAndAuditAlarm( 2227 _In_ PUNICODE_STRING SubsystemName, 2228 _In_opt_ PVOID HandleId, 2229 _In_ PUNICODE_STRING ObjectTypeName, 2230 _In_ PUNICODE_STRING ObjectName, 2231 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2232 _In_ ACCESS_MASK DesiredAccess, 2233 _In_ PGENERIC_MAPPING GenericMapping, 2234 _In_ BOOLEAN ObjectCreation, 2235 _Out_ PACCESS_MASK GrantedAccess, 2236 _Out_ PNTSTATUS AccessStatus, 2237 _Out_ PBOOLEAN GenerateOnClose) 2238 { 2239 /* Call the internal function */ 2240 return SepAccessCheckAndAuditAlarm(SubsystemName, 2241 HandleId, 2242 NULL, 2243 ObjectTypeName, 2244 ObjectName, 2245 SecurityDescriptor, 2246 NULL, 2247 DesiredAccess, 2248 AuditEventObjectAccess, 2249 0, 2250 NULL, 2251 0, 2252 GenericMapping, 2253 GrantedAccess, 2254 AccessStatus, 2255 GenerateOnClose, 2256 FALSE); 2257 } 2258 2259 /** 2260 * @brief 2261 * Raises an alarm audit message when a caller attempts to access an 2262 * object and determine if the access can be made by type. 2263 * 2264 * @param[in] SubsystemName 2265 * A Unicode string that points to a name of the subsystem. 2266 * 2267 * @param[in] HandleId 2268 * A handle to an ID that is used as identification instance for auditing. 2269 * 2270 * @param[in] ObjectTypeName 2271 * The name of the object type. 2272 * 2273 * @param[in] ObjectName 2274 * The object name. 2275 * 2276 * @param[in] SecurityDescriptor 2277 * A security descriptor. 2278 * 2279 * @param[in] PrincipalSelfSid 2280 * A principal self user SID. 2281 * 2282 * @param[in] DesiredAccess 2283 * The desired access rights masks requested by the caller. 2284 * 2285 * @param[in] AuditType 2286 * Type of audit to start, influencing how the audit should 2287 * be done. 2288 * 2289 * @param[in] Flags 2290 * Flag bitmask, used to check if auditing can be done 2291 * without privileges. 2292 * 2293 * @param[in] ObjectTypeList 2294 * A list of object types. 2295 * 2296 * @param[in] ObjectTypeLength 2297 * The length size of the list. 2298 * 2299 * @param[in] GenericMapping 2300 * The generic mapping of access mask rights. 2301 * 2302 * @param[in] ObjectCreation 2303 * Set this to TRUE if the object has just been created. 2304 * 2305 * @param[out] GrantedAccess 2306 * Returns the granted access rights. 2307 * 2308 * @param[out] AccessStatus 2309 * Returns a NTSTATUS status code indicating whether access check 2310 * can be granted or not. 2311 * 2312 * @param[out] GenerateOnClose 2313 * Returns TRUE if the function has generated a list of granted access rights and 2314 * status codes on termination, FALSE otherwise. 2315 * 2316 * @return 2317 * See SepAccessCheckAndAuditAlarm. 2318 */ 2319 _Must_inspect_result_ 2320 __kernel_entry 2321 NTSTATUS 2322 NTAPI 2323 NtAccessCheckByTypeAndAuditAlarm( 2324 _In_ PUNICODE_STRING SubsystemName, 2325 _In_opt_ PVOID HandleId, 2326 _In_ PUNICODE_STRING ObjectTypeName, 2327 _In_ PUNICODE_STRING ObjectName, 2328 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2329 _In_opt_ PSID PrincipalSelfSid, 2330 _In_ ACCESS_MASK DesiredAccess, 2331 _In_ AUDIT_EVENT_TYPE AuditType, 2332 _In_ ULONG Flags, 2333 _In_reads_opt_(ObjectTypeLength) POBJECT_TYPE_LIST ObjectTypeList, 2334 _In_ ULONG ObjectTypeLength, 2335 _In_ PGENERIC_MAPPING GenericMapping, 2336 _In_ BOOLEAN ObjectCreation, 2337 _Out_ PACCESS_MASK GrantedAccess, 2338 _Out_ PNTSTATUS AccessStatus, 2339 _Out_ PBOOLEAN GenerateOnClose) 2340 { 2341 /* Call the internal function */ 2342 return SepAccessCheckAndAuditAlarm(SubsystemName, 2343 HandleId, 2344 NULL, 2345 ObjectTypeName, 2346 ObjectName, 2347 SecurityDescriptor, 2348 PrincipalSelfSid, 2349 DesiredAccess, 2350 AuditType, 2351 Flags, 2352 ObjectTypeList, 2353 ObjectTypeLength, 2354 GenericMapping, 2355 GrantedAccess, 2356 AccessStatus, 2357 GenerateOnClose, 2358 FALSE); 2359 } 2360 2361 /** 2362 * @brief 2363 * Raises an alarm audit message when a caller attempts to access an 2364 * object and determine if the access can be made by given type result. 2365 * 2366 * @param[in] SubsystemName 2367 * A Unicode string that points to a name of the subsystem. 2368 * 2369 * @param[in] HandleId 2370 * A handle to an ID that is used as identification instance for auditing. 2371 * 2372 * @param[in] ObjectTypeName 2373 * The name of the object type. 2374 * 2375 * @param[in] ObjectName 2376 * The object name. 2377 * 2378 * @param[in] SecurityDescriptor 2379 * A security descriptor. 2380 * 2381 * @param[in] PrincipalSelfSid 2382 * A principal self user SID. 2383 * 2384 * @param[in] DesiredAccess 2385 * The desired access rights masks requested by the caller. 2386 * 2387 * @param[in] AuditType 2388 * Type of audit to start, influencing how the audit should 2389 * be done. 2390 * 2391 * @param[in] Flags 2392 * Flag bitmask, used to check if auditing can be done 2393 * without privileges. 2394 * 2395 * @param[in] ObjectTypeList 2396 * A list of object types. 2397 * 2398 * @param[in] ObjectTypeLength 2399 * The length size of the list. 2400 * 2401 * @param[in] GenericMapping 2402 * The generic mapping of access mask rights. 2403 * 2404 * @param[in] ObjectCreation 2405 * Set this to TRUE if the object has just been created. 2406 * 2407 * @param[out] GrantedAccessList 2408 * Returns the granted access rights. 2409 * 2410 * @param[out] AccessStatusList 2411 * Returns a NTSTATUS status code indicating whether access check 2412 * can be granted or not. 2413 * 2414 * @param[out] GenerateOnClose 2415 * Returns TRUE if the function has generated a list of granted access rights and 2416 * status codes on termination, FALSE otherwise. 2417 * 2418 * @return 2419 * See SepAccessCheckAndAuditAlarm. 2420 */ 2421 _Must_inspect_result_ 2422 __kernel_entry 2423 NTSTATUS 2424 NTAPI 2425 NtAccessCheckByTypeResultListAndAuditAlarm( 2426 _In_ PUNICODE_STRING SubsystemName, 2427 _In_opt_ PVOID HandleId, 2428 _In_ PUNICODE_STRING ObjectTypeName, 2429 _In_ PUNICODE_STRING ObjectName, 2430 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2431 _In_opt_ PSID PrincipalSelfSid, 2432 _In_ ACCESS_MASK DesiredAccess, 2433 _In_ AUDIT_EVENT_TYPE AuditType, 2434 _In_ ULONG Flags, 2435 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 2436 _In_ ULONG ObjectTypeListLength, 2437 _In_ PGENERIC_MAPPING GenericMapping, 2438 _In_ BOOLEAN ObjectCreation, 2439 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList, 2440 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList, 2441 _Out_ PBOOLEAN GenerateOnClose) 2442 { 2443 /* Call the internal function */ 2444 return SepAccessCheckAndAuditAlarm(SubsystemName, 2445 HandleId, 2446 NULL, 2447 ObjectTypeName, 2448 ObjectName, 2449 SecurityDescriptor, 2450 PrincipalSelfSid, 2451 DesiredAccess, 2452 AuditType, 2453 Flags, 2454 ObjectTypeList, 2455 ObjectTypeListLength, 2456 GenericMapping, 2457 GrantedAccessList, 2458 AccessStatusList, 2459 GenerateOnClose, 2460 TRUE); 2461 } 2462 2463 /** 2464 * @brief 2465 * Raises an alarm audit message when a caller attempts to access an 2466 * object and determine if the access can be made by given type result 2467 * and a token handle. 2468 * 2469 * @param[in] SubsystemName 2470 * A Unicode string that points to a name of the subsystem. 2471 * 2472 * @param[in] HandleId 2473 * A handle to an ID that is used as identification instance for auditing. 2474 * 2475 * @param[in] ClientToken 2476 * A handle to a client access token. 2477 * 2478 * @param[in] ObjectTypeName 2479 * The name of the object type. 2480 * 2481 * @param[in] ObjectName 2482 * The object name. 2483 * 2484 * @param[in] SecurityDescriptor 2485 * A security descriptor. 2486 * 2487 * @param[in] PrincipalSelfSid 2488 * A principal self user SID. 2489 * 2490 * @param[in] DesiredAccess 2491 * The desired access rights masks requested by the caller. 2492 * 2493 * @param[in] AuditType 2494 * Type of audit to start, influencing how the audit should 2495 * be done. 2496 * 2497 * @param[in] Flags 2498 * Flag bitmask, used to check if auditing can be done 2499 * without privileges. 2500 * 2501 * @param[in] ObjectTypeList 2502 * A list of object types. 2503 * 2504 * @param[in] ObjectTypeLength 2505 * The length size of the list. 2506 * 2507 * @param[in] GenericMapping 2508 * The generic mapping of access mask rights. 2509 * 2510 * @param[in] ObjectCreation 2511 * Set this to TRUE if the object has just been created. 2512 * 2513 * @param[out] GrantedAccessList 2514 * Returns the granted access rights. 2515 * 2516 * @param[out] AccessStatusList 2517 * Returns a NTSTATUS status code indicating whether access check 2518 * can be granted or not. 2519 * 2520 * @param[out] GenerateOnClose 2521 * Returns TRUE if the function has generated a list of granted access rights and 2522 * status codes on termination, FALSE otherwise. 2523 * 2524 * @return 2525 * See SepAccessCheckAndAuditAlarm. 2526 */ 2527 _Must_inspect_result_ 2528 __kernel_entry 2529 NTSTATUS 2530 NTAPI 2531 NtAccessCheckByTypeResultListAndAuditAlarmByHandle( 2532 _In_ PUNICODE_STRING SubsystemName, 2533 _In_opt_ PVOID HandleId, 2534 _In_ HANDLE ClientToken, 2535 _In_ PUNICODE_STRING ObjectTypeName, 2536 _In_ PUNICODE_STRING ObjectName, 2537 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 2538 _In_opt_ PSID PrincipalSelfSid, 2539 _In_ ACCESS_MASK DesiredAccess, 2540 _In_ AUDIT_EVENT_TYPE AuditType, 2541 _In_ ULONG Flags, 2542 _In_reads_opt_(ObjectTypeListLength) POBJECT_TYPE_LIST ObjectTypeList, 2543 _In_ ULONG ObjectTypeListLength, 2544 _In_ PGENERIC_MAPPING GenericMapping, 2545 _In_ BOOLEAN ObjectCreation, 2546 _Out_writes_(ObjectTypeListLength) PACCESS_MASK GrantedAccessList, 2547 _Out_writes_(ObjectTypeListLength) PNTSTATUS AccessStatusList, 2548 _Out_ PBOOLEAN GenerateOnClose) 2549 { 2550 UNREFERENCED_PARAMETER(ObjectCreation); 2551 2552 /* Call the internal function */ 2553 return SepAccessCheckAndAuditAlarm(SubsystemName, 2554 HandleId, 2555 &ClientToken, 2556 ObjectTypeName, 2557 ObjectName, 2558 SecurityDescriptor, 2559 PrincipalSelfSid, 2560 DesiredAccess, 2561 AuditType, 2562 Flags, 2563 ObjectTypeList, 2564 ObjectTypeListLength, 2565 GenericMapping, 2566 GrantedAccessList, 2567 AccessStatusList, 2568 GenerateOnClose, 2569 TRUE); 2570 } 2571 2572 /* EOF */ 2573