Reactos
at listview 1031 lines 31 kB view raw
1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * PURPOSE: Security manager 5 * FILE: lib/rtl/acl.c 6 * PROGRAMER: David Welch <welch@cwcom.net> 7 */ 8 9/* INCLUDES *****************************************************************/ 10 11#include <rtl.h> 12#include <../../ntoskrnl/include/internal/se.h> 13#define NDEBUG 14#include <debug.h> 15 16/* PRIVATE FUNCTIONS **********************************************************/ 17 18BOOLEAN 19NTAPI 20RtlFirstFreeAce(IN PACL Acl, 21 OUT PACE* FirstFreeAce) 22{ 23 PACE Current; 24 ULONG_PTR AclEnd; 25 ULONG i; 26 PAGED_CODE_RTL(); 27 28 /* Assume failure */ 29 *FirstFreeAce = NULL; 30 31 /* Get the start and end pointers */ 32 Current = (PACE)(Acl + 1); 33 AclEnd = (ULONG_PTR)Acl + Acl->AclSize; 34 35 /* Loop all the ACEs */ 36 for (i = 0; i < Acl->AceCount; i++) 37 { 38 /* If any is beyond the DACL, bail out, otherwise keep going */ 39 if ((ULONG_PTR)Current >= AclEnd) return FALSE; 40 Current = (PACE)((ULONG_PTR)Current + Current->Header.AceSize); 41 } 42 43 /* If the last spot is empty and still valid, return it */ 44 if ((ULONG_PTR)Current <= AclEnd) *FirstFreeAce = Current; 45 return TRUE; 46} 47 48VOID 49NTAPI 50RtlpAddData(IN PVOID AceList, 51 IN ULONG AceListLength, 52 IN PVOID Ace, 53 IN ULONG Offset) 54{ 55 /* Shift the buffer down */ 56 if (Offset > 0) 57 { 58 RtlCopyMemory((PVOID)((ULONG_PTR)Ace + AceListLength), 59 Ace, 60 Offset); 61 } 62 63 /* Copy the new data in */ 64 if (AceListLength) RtlCopyMemory(Ace, AceList, AceListLength); 65} 66 67VOID 68NTAPI 69RtlpDeleteData(IN PVOID Ace, 70 IN ULONG AceSize, 71 IN ULONG Offset) 72{ 73 /* Move the data up */ 74 if (AceSize < Offset) 75 { 76 RtlMoveMemory(Ace, 77 (PVOID)((ULONG_PTR)Ace + AceSize), 78 Offset - AceSize); 79 } 80 81 /* Zero the rest */ 82 if ((Offset - AceSize) < Offset) 83 { 84 RtlZeroMemory((PVOID)((ULONG_PTR)Ace + Offset - AceSize), AceSize); 85 } 86} 87 88NTSTATUS 89NTAPI 90RtlpAddKnownAce(IN PACL Acl, 91 IN ULONG Revision, 92 IN ULONG Flags, 93 IN ACCESS_MASK AccessMask, 94 IN PSID Sid, 95 IN UCHAR Type) 96{ 97 PKNOWN_ACE Ace; 98 ULONG AceSize, InvalidFlags; 99 PAGED_CODE_RTL(); 100 101 /* Check the validity of the SID */ 102 if (!RtlValidSid(Sid)) return STATUS_INVALID_SID; 103 104 /* Check the validity of the revision */ 105 if ((Acl->AclRevision > ACL_REVISION4) || (Revision > ACL_REVISION4)) 106 { 107 return STATUS_REVISION_MISMATCH; 108 } 109 110 /* Pick the smallest of the revisions */ 111 if (Revision < Acl->AclRevision) Revision = Acl->AclRevision; 112 113 /* Validate the flags */ 114 if (Type == SYSTEM_AUDIT_ACE_TYPE) 115 { 116 InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS | 117 SUCCESSFUL_ACCESS_ACE_FLAG | 118 FAILED_ACCESS_ACE_FLAG); 119 } 120 else 121 { 122 InvalidFlags = Flags & ~VALID_INHERIT_FLAGS; 123 } 124 125 /* If flags are invalid, bail out */ 126 if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER; 127 128 /* If ACL is invalid, bail out */ 129 if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL; 130 131 /* If there's no free ACE, bail out */ 132 if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL; 133 134 /* Calculate the size of the ACE and bail out if it's too small */ 135 AceSize = RtlLengthSid(Sid) + sizeof(ACE); 136 if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize)) 137 { 138 return STATUS_ALLOTTED_SPACE_EXCEEDED; 139 } 140 141 /* Initialize the header and common fields */ 142 Ace->Header.AceFlags = (BYTE)Flags; 143 Ace->Header.AceType = Type; 144 Ace->Header.AceSize = (WORD)AceSize; 145 Ace->Mask = AccessMask; 146 147 /* Copy the SID */ 148 RtlCopySid(RtlLengthSid(Sid), &Ace->SidStart, Sid); 149 150 /* Fill out the ACL header and return */ 151 Acl->AceCount++; 152 Acl->AclRevision = (BYTE)Revision; 153 return STATUS_SUCCESS; 154} 155 156NTSTATUS 157NTAPI 158RtlpAddKnownObjectAce(IN PACL Acl, 159 IN ULONG Revision, 160 IN ULONG Flags, 161 IN ACCESS_MASK AccessMask, 162 IN GUID *ObjectTypeGuid OPTIONAL, 163 IN GUID *InheritedObjectTypeGuid OPTIONAL, 164 IN PSID Sid, 165 IN UCHAR Type) 166{ 167 PKNOWN_OBJECT_ACE Ace; 168 ULONG_PTR SidStart; 169 ULONG AceSize, InvalidFlags, AceObjectFlags = 0; 170 PAGED_CODE_RTL(); 171 172 /* Check the validity of the SID */ 173 if (!RtlValidSid(Sid)) return STATUS_INVALID_SID; 174 175 /* Check the validity of the revision */ 176 if ((Acl->AclRevision > ACL_REVISION4) || (Revision != ACL_REVISION4)) 177 { 178 return STATUS_REVISION_MISMATCH; 179 } 180 181 /* Pick the smallest of the revisions */ 182 if (Revision < Acl->AclRevision) Revision = Acl->AclRevision; 183 184 /* Validate the flags */ 185 if ((Type == SYSTEM_AUDIT_OBJECT_ACE_TYPE) || 186 (Type == SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE)) 187 { 188 InvalidFlags = Flags & ~(VALID_INHERIT_FLAGS | 189 SUCCESSFUL_ACCESS_ACE_FLAG | FAILED_ACCESS_ACE_FLAG); 190 } 191 else 192 { 193 InvalidFlags = Flags & ~VALID_INHERIT_FLAGS; 194 } 195 196 /* If flags are invalid, bail out */ 197 if (InvalidFlags != 0) return STATUS_INVALID_PARAMETER; 198 199 /* If ACL is invalid, bail out */ 200 if (!RtlValidAcl(Acl)) return STATUS_INVALID_ACL; 201 202 /* If there's no free ACE, bail out */ 203 if (!RtlFirstFreeAce(Acl, (PACE*)&Ace)) return STATUS_INVALID_ACL; 204 205 /* Calculate the size of the ACE */ 206 AceSize = RtlLengthSid(Sid) + sizeof(ACE) + sizeof(ULONG); 207 208 /* Add-in the size of the GUIDs if any and update flags as needed */ 209 if (ObjectTypeGuid) 210 { 211 AceObjectFlags |= ACE_OBJECT_TYPE_PRESENT; 212 AceSize += sizeof(GUID); 213 } 214 if (InheritedObjectTypeGuid) 215 { 216 AceObjectFlags |= ACE_INHERITED_OBJECT_TYPE_PRESENT; 217 AceSize += sizeof(GUID); 218 } 219 220 /* Bail out if there's not enough space in the ACL */ 221 if (!(Ace) || ((ULONG_PTR)Ace + AceSize > (ULONG_PTR)Acl + Acl->AclSize)) 222 { 223 return STATUS_ALLOTTED_SPACE_EXCEEDED; 224 } 225 226 /* Initialize the header and common fields */ 227 Ace->Header.AceFlags = (BYTE)Flags; 228 Ace->Header.AceType = Type; 229 Ace->Header.AceSize = (WORD)AceSize; 230 Ace->Mask = AccessMask; 231 Ace->Flags = AceObjectFlags; 232 233 /* Copy the GUIDs */ 234 SidStart = (ULONG_PTR)&Ace->SidStart; 235 if (ObjectTypeGuid ) 236 { 237 RtlCopyMemory((PVOID)SidStart, ObjectTypeGuid, sizeof(GUID)); 238 SidStart += sizeof(GUID); 239 } 240 if (InheritedObjectTypeGuid) 241 { 242 RtlCopyMemory((PVOID)SidStart, InheritedObjectTypeGuid, sizeof(GUID)); 243 SidStart += sizeof(GUID); 244 } 245 246 /* Copy the SID */ 247 RtlCopySid(RtlLengthSid(Sid), (PSID)SidStart, Sid); 248 249 /* Fill out the ACL header and return */ 250 Acl->AceCount++; 251 Acl->AclRevision = (BYTE)Revision; 252 return STATUS_SUCCESS; 253} 254 255/* PUBLIC FUNCTIONS ***********************************************************/ 256 257/* 258 * @implemented 259 */ 260NTSTATUS 261NTAPI 262RtlAddAccessAllowedAce(IN OUT PACL Acl, 263 IN ULONG Revision, 264 IN ACCESS_MASK AccessMask, 265 IN PSID Sid) 266{ 267 PAGED_CODE_RTL(); 268 269 /* Call the worker function */ 270 return RtlpAddKnownAce(Acl, 271 Revision, 272 0, 273 AccessMask, 274 Sid, 275 ACCESS_ALLOWED_ACE_TYPE); 276} 277 278/* 279 * @implemented 280 */ 281NTSTATUS 282NTAPI 283RtlAddAccessAllowedAceEx(IN OUT PACL Acl, 284 IN ULONG Revision, 285 IN ULONG Flags, 286 IN ACCESS_MASK AccessMask, 287 IN PSID Sid) 288{ 289 PAGED_CODE_RTL(); 290 291 /* Call the worker function */ 292 return RtlpAddKnownAce(Acl, 293 Revision, 294 Flags, 295 AccessMask, 296 Sid, 297 ACCESS_ALLOWED_ACE_TYPE); 298} 299 300/* 301 * @implemented 302 */ 303NTSTATUS 304NTAPI 305RtlAddAccessAllowedObjectAce(IN OUT PACL Acl, 306 IN ULONG Revision, 307 IN ULONG Flags, 308 IN ACCESS_MASK AccessMask, 309 IN GUID *ObjectTypeGuid OPTIONAL, 310 IN GUID *InheritedObjectTypeGuid OPTIONAL, 311 IN PSID Sid) 312{ 313 PAGED_CODE_RTL(); 314 315 /* Is there no object data? */ 316 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) 317 { 318 /* Use the usual routine */ 319 return RtlpAddKnownAce(Acl, 320 Revision, 321 Flags, 322 AccessMask, 323 Sid, 324 ACCESS_ALLOWED_ACE_TYPE); 325 } 326 327 /* Use the object routine */ 328 return RtlpAddKnownObjectAce(Acl, 329 Revision, 330 Flags, 331 AccessMask, 332 ObjectTypeGuid, 333 InheritedObjectTypeGuid, 334 Sid, 335 ACCESS_ALLOWED_OBJECT_ACE_TYPE); 336} 337 338/* 339 * @implemented 340 */ 341NTSTATUS 342NTAPI 343RtlAddAccessDeniedAce(IN PACL Acl, 344 IN ULONG Revision, 345 IN ACCESS_MASK AccessMask, 346 IN PSID Sid) 347{ 348 PAGED_CODE_RTL(); 349 350 /* Call the worker function */ 351 return RtlpAddKnownAce(Acl, 352 Revision, 353 0, 354 AccessMask, 355 Sid, 356 ACCESS_DENIED_ACE_TYPE); 357} 358 359/* 360 * @implemented 361 */ 362NTSTATUS 363NTAPI 364RtlAddAccessDeniedAceEx(IN OUT PACL Acl, 365 IN ULONG Revision, 366 IN ULONG Flags, 367 IN ACCESS_MASK AccessMask, 368 IN PSID Sid) 369{ 370 PAGED_CODE_RTL(); 371 372 /* Call the worker function */ 373 return RtlpAddKnownAce(Acl, 374 Revision, 375 Flags, 376 AccessMask, 377 Sid, 378 ACCESS_DENIED_ACE_TYPE); 379} 380 381/* 382 * @implemented 383 */ 384NTSTATUS 385NTAPI 386RtlAddAccessDeniedObjectAce(IN OUT PACL Acl, 387 IN ULONG Revision, 388 IN ULONG Flags, 389 IN ACCESS_MASK AccessMask, 390 IN GUID *ObjectTypeGuid OPTIONAL, 391 IN GUID *InheritedObjectTypeGuid OPTIONAL, 392 IN PSID Sid) 393{ 394 PAGED_CODE_RTL(); 395 396 /* Is there no object data? */ 397 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) 398 { 399 /* Use the usual routine */ 400 return RtlpAddKnownAce(Acl, 401 Revision, 402 Flags, 403 AccessMask, 404 Sid, 405 ACCESS_DENIED_ACE_TYPE); 406 } 407 408 /* There's object data, use the object routine */ 409 return RtlpAddKnownObjectAce(Acl, 410 Revision, 411 Flags, 412 AccessMask, 413 ObjectTypeGuid, 414 InheritedObjectTypeGuid, 415 Sid, 416 ACCESS_DENIED_OBJECT_ACE_TYPE); 417} 418 419/* 420 * @implemented 421 */ 422NTSTATUS 423NTAPI 424RtlAddAuditAccessAce(IN PACL Acl, 425 IN ULONG Revision, 426 IN ACCESS_MASK AccessMask, 427 IN PSID Sid, 428 IN BOOLEAN Success, 429 IN BOOLEAN Failure) 430{ 431 ULONG Flags = 0; 432 PAGED_CODE_RTL(); 433 434 /* Add flags */ 435 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 436 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG; 437 438 /* Call the worker routine */ 439 return RtlpAddKnownAce(Acl, 440 Revision, 441 Flags, 442 AccessMask, 443 Sid, 444 SYSTEM_AUDIT_ACE_TYPE); 445} 446 447/* 448 * @implemented 449 */ 450NTSTATUS 451NTAPI 452RtlAddAuditAccessAceEx(IN PACL Acl, 453 IN ULONG Revision, 454 IN ULONG Flags, 455 IN ACCESS_MASK AccessMask, 456 IN PSID Sid, 457 IN BOOLEAN Success, 458 IN BOOLEAN Failure) 459{ 460 PAGED_CODE_RTL(); 461 462 /* Add flags */ 463 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 464 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG; 465 466 /* Call the worker routine */ 467 return RtlpAddKnownAce(Acl, 468 Revision, 469 Flags, 470 AccessMask, 471 Sid, 472 SYSTEM_AUDIT_ACE_TYPE); 473} 474 475/* 476 * @implemented 477 */ 478NTSTATUS 479NTAPI 480RtlAddAuditAccessObjectAce(IN PACL Acl, 481 IN ULONG Revision, 482 IN ULONG Flags, 483 IN ACCESS_MASK AccessMask, 484 IN GUID *ObjectTypeGuid OPTIONAL, 485 IN GUID *InheritedObjectTypeGuid OPTIONAL, 486 IN PSID Sid, 487 IN BOOLEAN Success, 488 IN BOOLEAN Failure) 489{ 490 /* Add flags */ 491 if (Success) Flags |= SUCCESSFUL_ACCESS_ACE_FLAG; 492 if (Failure) Flags |= FAILED_ACCESS_ACE_FLAG; 493 494 /* Is there no object data? */ 495 if (!(ObjectTypeGuid) && !(InheritedObjectTypeGuid)) 496 { 497 /* Call the normal routine */ 498 return RtlpAddKnownAce(Acl, 499 Revision, 500 Flags, 501 AccessMask, 502 Sid, 503 SYSTEM_AUDIT_ACE_TYPE); 504 } 505 506 /* There's object data, use the object routine */ 507 return RtlpAddKnownObjectAce(Acl, 508 Revision, 509 Flags, 510 AccessMask, 511 ObjectTypeGuid, 512 InheritedObjectTypeGuid, 513 Sid, 514 SYSTEM_AUDIT_OBJECT_ACE_TYPE); 515} 516 517/* 518 * @implemented 519 */ 520NTSTATUS 521NTAPI 522RtlGetAce(IN PACL Acl, 523 IN ULONG AceIndex, 524 OUT PVOID *Ace) 525{ 526 ULONG i; 527 PAGED_CODE_RTL(); 528 529 /* Bail out if the revision or the index are invalid */ 530 if ((Acl->AclRevision < MIN_ACL_REVISION) || 531 (Acl->AclRevision > MAX_ACL_REVISION) || 532 (AceIndex >= Acl->AceCount)) 533 { 534 return STATUS_INVALID_PARAMETER; 535 } 536 537 /* Loop through the ACEs */ 538 *Ace = (PVOID)((PACE)(Acl + 1)); 539 for (i = 0; i < AceIndex; i++) 540 { 541 /* Bail out if an invalid ACE is ever found */ 542 if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize) 543 { 544 return STATUS_INVALID_PARAMETER; 545 } 546 547 /* Keep going */ 548 *Ace = (PVOID)((PACE)((ULONG_PTR)(*Ace) + ((PACE)(*Ace))->Header.AceSize)); 549 } 550 551 /* Check if the last ACE is still valid */ 552 if ((ULONG_PTR)*Ace >= (ULONG_PTR)Acl + Acl->AclSize) 553 { 554 return STATUS_INVALID_PARAMETER; 555 } 556 557 /* All good, return */ 558 return STATUS_SUCCESS; 559} 560 561/* 562 * @implemented 563 */ 564NTSTATUS 565NTAPI 566RtlAddAce(IN PACL Acl, 567 IN ULONG AclRevision, 568 IN ULONG StartingIndex, 569 IN PVOID AceList, 570 IN ULONG AceListLength) 571{ 572 PACE Ace, FreeAce; 573 USHORT NewAceCount; 574 ULONG Index; 575 PAGED_CODE_RTL(); 576 577 /* Bail out if the ACL is invalid */ 578 if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER; 579 580 /* Bail out if there's no space */ 581 if (!RtlFirstFreeAce(Acl, &FreeAce)) return STATUS_INVALID_PARAMETER; 582 583 /* Loop over all the ACEs, keeping track of new ACEs as we go along */ 584 for (Ace = AceList, NewAceCount = 0; 585 Ace < (PACE)((ULONG_PTR)AceList + AceListLength); 586 NewAceCount++) 587 { 588 /* Make sure that the revision of this ACE is valid in this list. 589 The initial check looks strange, but it is what Windows does. */ 590 if (Ace->Header.AceType <= ACCESS_MAX_MS_ACE_TYPE) 591 { 592 if (Ace->Header.AceType > ACCESS_MAX_MS_V3_ACE_TYPE) 593 { 594 if (AclRevision < ACL_REVISION4) return STATUS_INVALID_PARAMETER; 595 } 596 else if (Ace->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE) 597 { 598 if (AclRevision < ACL_REVISION3) return STATUS_INVALID_PARAMETER; 599 } 600 } 601 602 /* Move to the next ACE */ 603 Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize); 604 } 605 606 /* Bail out if there's no more space for us */ 607 if ((ULONG_PTR)Ace > ((ULONG_PTR)AceList + AceListLength)) 608 { 609 return STATUS_INVALID_PARAMETER; 610 } 611 612 /* Bail out if there's no free ACE spot, or if we would overflow it */ 613 if (!(FreeAce) || 614 ((ULONG_PTR)FreeAce + AceListLength > (ULONG_PTR)Acl + Acl->AclSize)) 615 { 616 return STATUS_BUFFER_TOO_SMALL; 617 } 618 619 /* Go down the list until we find our index */ 620 Ace = (PACE)(Acl + 1); 621 for (Index = 0; (Index < StartingIndex) && (Index < Acl->AceCount); Index++) 622 { 623 Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize); 624 } 625 626 /* Found where we want to do, add us to the list */ 627 RtlpAddData(AceList, 628 AceListLength, 629 Ace, 630 (ULONG_PTR)FreeAce - (ULONG_PTR)Ace); 631 632 /* Update the header and return */ 633 Acl->AceCount += NewAceCount; 634 Acl->AclRevision = (UCHAR)min(Acl->AclRevision, AclRevision); 635 return STATUS_SUCCESS; 636} 637 638/* 639 * @implemented 640 */ 641NTSTATUS 642NTAPI 643RtlDeleteAce(IN PACL Acl, 644 IN ULONG AceIndex) 645{ 646 PACE FreeAce, Ace; 647 PAGED_CODE_RTL(); 648 649 /* Bail out if the ACL is invalid */ 650 if (!RtlValidAcl(Acl)) return STATUS_INVALID_PARAMETER; 651 652 /* Bail out if there's no space or if we're full */ 653 if ((Acl->AceCount <= AceIndex) || !(RtlFirstFreeAce(Acl, &FreeAce))) 654 { 655 return STATUS_INVALID_PARAMETER; 656 } 657 658 /* Enumerate until the indexed ACE is reached */ 659 Ace = (PACE)(Acl + 1); 660 while (AceIndex--) Ace = (PACE)((ULONG_PTR)Ace + Ace->Header.AceSize); 661 662 /* Delete this ACE */ 663 RtlpDeleteData(Ace, 664 Ace->Header.AceSize, 665 (ULONG)((ULONG_PTR)FreeAce - (ULONG_PTR)Ace)); 666 667 /* Decrease an ACE and return success */ 668 Acl->AceCount--; 669 return STATUS_SUCCESS; 670} 671 672/* 673 * @implemented 674 */ 675NTSTATUS 676NTAPI 677RtlCreateAcl(IN PACL Acl, 678 IN ULONG AclSize, 679 IN ULONG AclRevision) 680{ 681 PAGED_CODE_RTL(); 682 683 /* Bail out if too small */ 684 if (AclSize < sizeof(ACL)) return STATUS_BUFFER_TOO_SMALL; 685 686 /* Bail out if too large or invalid revision */ 687 if ((AclRevision < MIN_ACL_REVISION) || 688 (AclRevision > MAX_ACL_REVISION) || 689 (AclSize > MAXUSHORT)) 690 { 691 return STATUS_INVALID_PARAMETER; 692 } 693 694 /* Setup the header */ 695 Acl->AclSize = (USHORT)ROUND_UP(AclSize, 4); 696 Acl->AclRevision = (UCHAR)AclRevision; 697 Acl->AceCount = 0; 698 Acl->Sbz1 = 0; 699 Acl->Sbz2 = 0; 700 return STATUS_SUCCESS; 701} 702 703/* 704 * @implemented 705 */ 706NTSTATUS 707NTAPI 708RtlQueryInformationAcl(IN PACL Acl, 709 IN PVOID Information, 710 IN ULONG InformationLength, 711 IN ACL_INFORMATION_CLASS InformationClass) 712{ 713 PACE Ace; 714 PACL_REVISION_INFORMATION RevisionInfo; 715 PACL_SIZE_INFORMATION SizeInfo; 716 PAGED_CODE_RTL(); 717 718 /* Validate the ACL revision */ 719 if ((Acl->AclRevision < MIN_ACL_REVISION) || 720 (Acl->AclRevision > MAX_ACL_REVISION)) 721 { 722 return STATUS_INVALID_PARAMETER; 723 } 724 725 /* Check what the caller is querying */ 726 switch (InformationClass) 727 { 728 /* Revision data */ 729 case AclRevisionInformation: 730 731 /* Bail out if the buffer is too small */ 732 if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) 733 { 734 return STATUS_BUFFER_TOO_SMALL; 735 } 736 737 /* Return the current revision */ 738 RevisionInfo = (PACL_REVISION_INFORMATION)Information; 739 RevisionInfo->AclRevision = Acl->AclRevision; 740 break; 741 742 /* Size data */ 743 case AclSizeInformation: 744 745 /* Bail out if the buffer is too small */ 746 if (InformationLength < sizeof(ACL_SIZE_INFORMATION)) 747 { 748 return STATUS_BUFFER_TOO_SMALL; 749 } 750 751 /* Bail out if there's no space in the ACL */ 752 if (!RtlFirstFreeAce(Acl, &Ace)) return STATUS_INVALID_PARAMETER; 753 754 /* Read the number of ACEs and check if there was a free ACE */ 755 SizeInfo = (PACL_SIZE_INFORMATION)Information; 756 SizeInfo->AceCount = Acl->AceCount; 757 if (Ace) 758 { 759 /* Return how much space there is in the ACL */ 760 SizeInfo->AclBytesInUse = (ULONG_PTR)Ace - (ULONG_PTR)Acl; 761 SizeInfo->AclBytesFree = Acl->AclSize - SizeInfo->AclBytesInUse; 762 } 763 else 764 { 765 /* No free ACE, means the whole ACL is full */ 766 SizeInfo->AclBytesInUse = Acl->AclSize; 767 SizeInfo->AclBytesFree = 0; 768 } 769 break; 770 771 default: 772 /* Anything else is illegal */ 773 return STATUS_INVALID_INFO_CLASS; 774 } 775 776 /* All done */ 777 return STATUS_SUCCESS; 778} 779 780/* 781 * @implemented 782 */ 783NTSTATUS 784NTAPI 785RtlSetInformationAcl(IN PACL Acl, 786 IN PVOID Information, 787 IN ULONG InformationLength, 788 IN ACL_INFORMATION_CLASS InformationClass) 789{ 790 PACL_REVISION_INFORMATION Info ; 791 PAGED_CODE_RTL(); 792 793 /* Validate the ACL revision */ 794 if ((Acl->AclRevision < MIN_ACL_REVISION) || 795 (Acl->AclRevision > MAX_ACL_REVISION)) 796 { 797 return STATUS_INVALID_PARAMETER; 798 } 799 800 /* What is the caller trying to set? */ 801 switch (InformationClass) 802 { 803 /* This is the only info class */ 804 case AclRevisionInformation: 805 806 /* Make sure the buffer is large enough */ 807 if (InformationLength < sizeof(ACL_REVISION_INFORMATION)) 808 { 809 return STATUS_BUFFER_TOO_SMALL; 810 } 811 812 /* Make sure the new revision is within the acceptable bounds*/ 813 Info = (PACL_REVISION_INFORMATION)Information; 814 if (Acl->AclRevision >= Info->AclRevision) 815 { 816 return STATUS_INVALID_PARAMETER; 817 } 818 819 /* Set the new revision */ 820 Acl->AclRevision = (BYTE)Info->AclRevision; 821 break; 822 823 default: 824 /* Anything else is invalid */ 825 return STATUS_INVALID_INFO_CLASS; 826 } 827 828 /* All good */ 829 return STATUS_SUCCESS; 830} 831 832/* 833 * @implemented 834 */ 835BOOLEAN 836NTAPI 837RtlValidAcl(IN PACL Acl) 838{ 839 PACE_HEADER Ace; 840 PISID Sid; 841 ULONG i; 842 USHORT RequiredObjectAceSize; 843 PULONG Flags; 844 ULONG GuidSize; 845 PAGED_CODE_RTL(); 846 847 _SEH2_TRY 848 { 849 /* First, validate the revision */ 850 if ((Acl->AclRevision < MIN_ACL_REVISION) || 851 (Acl->AclRevision > MAX_ACL_REVISION)) 852 { 853 DPRINT1("Invalid ACL revision: %u\n", Acl->AclRevision); 854 _SEH2_YIELD(return FALSE); 855 } 856 857 /* Next, validate that the ACL is USHORT-aligned */ 858 if (ROUND_DOWN(Acl->AclSize, sizeof(USHORT)) != Acl->AclSize) 859 { 860 DPRINT1("Misaligned ACL size: %u\n", Acl->AclSize); 861 _SEH2_YIELD(return FALSE); 862 } 863 864 /* And that it's big enough */ 865 if (Acl->AclSize < sizeof(ACL)) 866 { 867 DPRINT1("Too small ACL size: %u\n", Acl->AclSize); 868 _SEH2_YIELD(return FALSE); 869 } 870 871 /* Loop each ACE */ 872 Ace = (PACE_HEADER)((ULONG_PTR)Acl + sizeof(ACL)); 873 for (i = 0; i < Acl->AceCount; i++) 874 { 875 /* Validate we have space for this ACE header */ 876 if (((ULONG_PTR)Ace + sizeof(ACE_HEADER)) >= ((ULONG_PTR)Acl + Acl->AclSize)) 877 { 878 DPRINT1("Invalid ACE size\n"); 879 _SEH2_YIELD(return FALSE); 880 } 881 882 /* Validate the length of this ACE */ 883 if (ROUND_DOWN(Ace->AceSize, sizeof(USHORT)) != Ace->AceSize) 884 { 885 DPRINT1("Invalid ACE size: %lx\n", Ace->AceSize); 886 _SEH2_YIELD(return FALSE); 887 } 888 889 /* Validate we have space for the entire ACE */ 890 if (((ULONG_PTR)Ace + Ace->AceSize) > ((ULONG_PTR)Acl + Acl->AclSize)) 891 { 892 DPRINT1("Invalid ACE size %lx %lx\n", Ace->AceSize, Acl->AclSize); 893 _SEH2_YIELD(return FALSE); 894 } 895 896 /* Check what kind of ACE this is */ 897 if (Ace->AceType <= ACCESS_MAX_MS_V2_ACE_TYPE) 898 { 899 /* Validate the length of this ACE */ 900 if (ROUND_DOWN(Ace->AceSize, sizeof(ULONG)) != Ace->AceSize) 901 { 902 DPRINT1("Invalid ACE size\n"); 903 _SEH2_YIELD(return FALSE); 904 } 905 906 /* The ACE size should at least have enough for the header */ 907 if (Ace->AceSize < sizeof(ACE_HEADER)) 908 { 909 DPRINT1("Invalid ACE size: %lx %lx\n", Ace->AceSize, sizeof(ACE_HEADER)); 910 _SEH2_YIELD(return FALSE); 911 } 912 913 /* Check if the SID revision is valid */ 914 Sid = (PISID)&((PKNOWN_ACE)Ace)->SidStart; 915 if (Sid->Revision != SID_REVISION) 916 { 917 DPRINT1("Invalid SID\n"); 918 _SEH2_YIELD(return FALSE); 919 } 920 921 /* Check if the SID is out of bounds */ 922 if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) 923 { 924 DPRINT1("Invalid SID\n"); 925 _SEH2_YIELD(return FALSE); 926 } 927 928 /* The ACE size should at least have enough for the header and SID */ 929 if (Ace->AceSize < (sizeof(ACE_HEADER) + RtlLengthSid(Sid))) 930 { 931 DPRINT1("Invalid ACE size\n"); 932 _SEH2_YIELD(return FALSE); 933 } 934 } 935 else if (Ace->AceType == ACCESS_ALLOWED_OBJECT_ACE_TYPE || 936 Ace->AceType == ACCESS_DENIED_OBJECT_ACE_TYPE) 937 { 938 /* Object ACEs are supported starting with Revision 4 */ 939 if (Acl->AclRevision < ACL_REVISION4) 940 { 941 DPRINT1("Invalid ACL revision for Object ACE: %u\n", Acl->AclRevision); 942 _SEH2_YIELD(return FALSE); 943 } 944 945 /* Validate the length of this ACE */ 946 if (ROUND_DOWN(Ace->AceSize, sizeof(ULONG)) != Ace->AceSize) 947 { 948 DPRINT1("Misaligned Object ACE size: %lx\n", Ace->AceSize); 949 _SEH2_YIELD(return FALSE); 950 } 951 952 /* The ACE size should at least have enough space for the known object ACE header */ 953 if (Ace->AceSize < sizeof(KNOWN_OBJECT_ACE)) 954 { 955 DPRINT1("Too small Object ACE size to hold KNOWN_OBJECT_ACE header: %lx\n", Ace->AceSize); 956 _SEH2_YIELD(return FALSE); 957 } 958 959 /* This ACL may have multiple Object ACEs so reset the size counter */ 960 GuidSize = 0; 961 962 /* If we have GUIDs include them */ 963 Flags = (PULONG)&((PKNOWN_OBJECT_ACE)Ace)->Flags; 964 if (*Flags & ACE_OBJECT_TYPE_PRESENT) 965 { 966 GuidSize += sizeof(GUID); 967 } 968 969 if (*Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT) 970 { 971 GuidSize += sizeof(GUID); 972 } 973 974 /* Check if the SID revision is valid */ 975 Sid = (PISID)((ULONG_PTR)&((PKNOWN_OBJECT_ACE)Ace)->SidStart + GuidSize); 976 if (Sid->Revision != SID_REVISION) 977 { 978 DPRINT1("Object ACE SID has invalid revision: %u\n", Sid->Revision); 979 _SEH2_YIELD(return FALSE); 980 } 981 982 /* Check if the SID is out of bounds */ 983 if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) 984 { 985 DPRINT1("Object ACE SID's sub-authority count is out of bounds: %u\n", Sid->SubAuthorityCount); 986 _SEH2_YIELD(return FALSE); 987 } 988 989 /* The ACE size should at least have enough space for the known object ACE header, GUIDs and the SID */ 990 RequiredObjectAceSize = (sizeof(KNOWN_OBJECT_ACE) - sizeof(ULONG)) + GuidSize + RtlLengthSid(Sid); 991 if (Ace->AceSize < RequiredObjectAceSize) 992 { 993 DPRINT1("Too small Object ACE size: AceSize %u RequiredSize %u\n", Ace->AceSize, RequiredObjectAceSize); 994 _SEH2_YIELD(return FALSE); 995 } 996 } 997 else if (Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE) 998 { 999 DPRINT1("Unsupported ACE in ReactOS, assuming valid\n"); 1000 } 1001 else if ((Ace->AceType >= ACCESS_MIN_MS_OBJECT_ACE_TYPE) && 1002 (Ace->AceType <= ACCESS_MAX_MS_OBJECT_ACE_TYPE)) 1003 { 1004 DPRINT1("Unsupported ACE in ReactOS, assuming valid\n"); 1005 } 1006 else 1007 { 1008 /* Unknown ACE, see if it's as big as a header at least */ 1009 if (Ace->AceSize < sizeof(ACE_HEADER)) 1010 { 1011 DPRINT1("Unknown ACE\n"); 1012 _SEH2_YIELD(return FALSE); 1013 } 1014 } 1015 1016 /* Move to the next ace */ 1017 Ace = (PACE_HEADER)((ULONG_PTR)Ace + Ace->AceSize); 1018 } 1019 } 1020 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1021 { 1022 /* Something was invalid, fail */ 1023 _SEH2_YIELD(return FALSE); 1024 } 1025 _SEH2_END; 1026 1027 /* The ACL looks ok */ 1028 return TRUE; 1029} 1030 1031/* EOF */