1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * PURPOSE: Boot Data implementation 5 * FILE: lib/rtl/bootdata.c 6 * PROGRAMMERS: 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <rtl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* FUNCTIONS *****************************************************************/ 16 17 static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY}; 18 19 static NTSTATUS 20 RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor, 21 OUT PSID *SystemSid) 22 { 23 PSECURITY_DESCRIPTOR AbsSD = NULL; 24 PSID LocalSystemSid = NULL; 25 PACL Dacl = NULL; 26 ULONG DaclSize; 27 NTSTATUS Status; 28 29 /* create the local SYSTEM SID */ 30 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 31 1, 32 SECURITY_LOCAL_SYSTEM_RID, 33 0, 34 0, 35 0, 36 0, 37 0, 38 0, 39 0, 40 &LocalSystemSid); 41 if (!NT_SUCCESS(Status)) 42 { 43 return Status; 44 } 45 46 /* allocate and initialize the security descriptor */ 47 AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR), 48 'dSeS'); 49 if (AbsSD == NULL) 50 { 51 Status = STATUS_NO_MEMORY; 52 goto Cleanup; 53 } 54 55 Status = RtlCreateSecurityDescriptor(AbsSD, 56 SECURITY_DESCRIPTOR_REVISION); 57 if (!NT_SUCCESS(Status)) 58 { 59 goto Cleanup; 60 } 61 62 /* allocate and create the DACL */ 63 DaclSize = sizeof(ACL) + sizeof(ACE) + 64 RtlLengthSid(LocalSystemSid); 65 Dacl = RtlpAllocateMemory(DaclSize, 66 'cAeS'); 67 if (Dacl == NULL) 68 { 69 Status = STATUS_NO_MEMORY; 70 goto Cleanup; 71 } 72 73 Status = RtlCreateAcl(Dacl, 74 DaclSize, 75 ACL_REVISION); 76 if (!NT_SUCCESS(Status)) 77 { 78 goto Cleanup; 79 } 80 81 Status = RtlAddAccessAllowedAceEx(Dacl, 82 ACL_REVISION, 83 OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE, 84 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, 85 LocalSystemSid); 86 if (!NT_SUCCESS(Status)) 87 { 88 goto Cleanup; 89 } 90 91 /* set the DACL in the security descriptor */ 92 Status = RtlSetDaclSecurityDescriptor(AbsSD, 93 TRUE, 94 Dacl, 95 FALSE); 96 97 /* all done */ 98 if (NT_SUCCESS(Status)) 99 { 100 *SecurityDescriptor = AbsSD; 101 *SystemSid = LocalSystemSid; 102 } 103 else 104 { 105 Cleanup: 106 if (LocalSystemSid != NULL) 107 { 108 RtlFreeSid(LocalSystemSid); 109 } 110 111 if (Dacl != NULL) 112 { 113 RtlpFreeMemory(Dacl, 114 'cAeS'); 115 } 116 117 if (AbsSD != NULL) 118 { 119 RtlpFreeMemory(AbsSD, 120 'dSeS'); 121 } 122 } 123 124 return Status; 125 } 126 127 static NTSTATUS 128 RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle, 129 IN PISECURITY_DESCRIPTOR SecurityDescriptor) 130 { 131 PSECURITY_DESCRIPTOR RelSD = NULL; 132 PSECURITY_DESCRIPTOR NewRelSD = NULL; 133 PSECURITY_DESCRIPTOR AbsSD = NULL; 134 #ifdef _WIN64 135 BOOLEAN AbsSDAllocated = FALSE; 136 #endif 137 PSID AdminSid = NULL; 138 PSID LocalSystemSid = NULL; 139 ULONG DescriptorSize; 140 ULONG AbsSDSize, RelSDSize = 0; 141 PACL Dacl; 142 BOOLEAN DaclPresent, DaclDefaulted; 143 PSID OwnerSid; 144 BOOLEAN OwnerDefaulted; 145 ULONG AceIndex; 146 PACE Ace = NULL; 147 NTSTATUS Status; 148 149 /* find out how much memory we need to allocate for the self-relative 150 descriptor we're querying */ 151 Status = ZwQuerySecurityObject(DirectoryHandle, 152 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, 153 NULL, 154 0, 155 &DescriptorSize); 156 if (Status != STATUS_BUFFER_TOO_SMALL) 157 { 158 /* looks like the FS doesn't support security... return success */ 159 Status = STATUS_SUCCESS; 160 goto Cleanup; 161 } 162 163 /* allocate enough memory for the security descriptor */ 164 RelSD = RtlpAllocateMemory(DescriptorSize, 165 'dSeS'); 166 if (RelSD == NULL) 167 { 168 Status = STATUS_NO_MEMORY; 169 goto Cleanup; 170 } 171 172 /* query the self-relative security descriptor */ 173 Status = ZwQuerySecurityObject(DirectoryHandle, 174 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, 175 RelSD, 176 DescriptorSize, 177 &DescriptorSize); 178 if (!NT_SUCCESS(Status)) 179 { 180 /* FIXME - handle the case where someone else modified the owner and/or 181 DACL while we allocated memory. But that should be *very* 182 unlikely.... */ 183 goto Cleanup; 184 } 185 186 /* query the owner and DACL from the descriptor */ 187 Status = RtlGetOwnerSecurityDescriptor(RelSD, 188 &OwnerSid, 189 &OwnerDefaulted); 190 if (!NT_SUCCESS(Status)) 191 { 192 goto Cleanup; 193 } 194 195 Status = RtlGetDaclSecurityDescriptor(RelSD, 196 &DaclPresent, 197 &Dacl, 198 &DaclDefaulted); 199 if (!NT_SUCCESS(Status)) 200 { 201 goto Cleanup; 202 } 203 204 /* create the Administrators SID */ 205 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 206 2, 207 SECURITY_BUILTIN_DOMAIN_RID, 208 DOMAIN_ALIAS_RID_ADMINS, 209 0, 210 0, 211 0, 212 0, 213 0, 214 0, 215 &AdminSid); 216 if (!NT_SUCCESS(Status)) 217 { 218 goto Cleanup; 219 } 220 221 /* create the local SYSTEM SID */ 222 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 223 1, 224 SECURITY_LOCAL_SYSTEM_RID, 225 0, 226 0, 227 0, 228 0, 229 0, 230 0, 231 0, 232 &LocalSystemSid); 233 if (!NT_SUCCESS(Status)) 234 { 235 goto Cleanup; 236 } 237 238 /* check if the Administrators are the owner and at least a not-NULL DACL 239 is present */ 240 if (OwnerSid != NULL && 241 RtlEqualSid(OwnerSid, 242 AdminSid) && 243 DaclPresent && Dacl != NULL) 244 { 245 /* check the DACL for an Allowed ACE for the SYSTEM account */ 246 AceIndex = 0; 247 do 248 { 249 Status = RtlGetAce(Dacl, 250 AceIndex++, 251 (PVOID*)&Ace); 252 if (!NT_SUCCESS(Status)) 253 { 254 Ace = NULL; 255 } 256 else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) 257 { 258 /* check if the the ACE is a set of allowed permissions for the 259 local SYSTEM account */ 260 if (RtlEqualSid((PSID)(Ace + 1), 261 LocalSystemSid)) 262 { 263 /* check if the ACE is inherited by noncontainer and 264 container objects, if not attempt to change that */ 265 if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) || 266 !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE)) 267 { 268 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; 269 Status = ZwSetSecurityObject(DirectoryHandle, 270 DACL_SECURITY_INFORMATION, 271 RelSD); 272 } 273 else 274 { 275 /* all done, we have access */ 276 Status = STATUS_SUCCESS; 277 } 278 279 goto Cleanup; 280 } 281 } 282 } while (Ace != NULL); 283 } 284 285 AbsSDSize = DescriptorSize; 286 287 /* because we need to change any existing data we need to convert it to 288 an absolute security descriptor first */ 289 Status = RtlSelfRelativeToAbsoluteSD2(RelSD, 290 &AbsSDSize); 291 #ifdef _WIN64 292 if (Status == STATUS_BUFFER_TOO_SMALL) 293 { 294 /* this error code can only be returned on 64 bit builds because 295 the size of an absolute security descriptor is greater than the 296 size of a self-relative security descriptor */ 297 ASSERT(AbsSDSize > DescriptorSize); 298 299 AbsSD = RtlpAllocateMemory(DescriptorSize, 300 'dSeS'); 301 if (AbsSD == NULL) 302 { 303 Status = STATUS_NO_MEMORY; 304 goto Cleanup; 305 } 306 307 AbsSDAllocated = TRUE; 308 309 /* make a raw copy of the self-relative descriptor */ 310 RtlCopyMemory(AbsSD, 311 RelSD, 312 DescriptorSize); 313 314 /* finally convert it */ 315 Status = RtlSelfRelativeToAbsoluteSD2(AbsSD, 316 &AbsSDSize); 317 } 318 else 319 #endif 320 { 321 AbsSD = RelSD; 322 } 323 324 if (!NT_SUCCESS(Status)) 325 { 326 goto Cleanup; 327 } 328 329 /* set the owner SID */ 330 Status = RtlSetOwnerSecurityDescriptor(AbsSD, 331 AdminSid, 332 FALSE); 333 if (!NT_SUCCESS(Status)) 334 { 335 goto Cleanup; 336 } 337 338 /* set the DACL in the security descriptor */ 339 Status = RtlSetDaclSecurityDescriptor(AbsSD, 340 TRUE, 341 SecurityDescriptor->Dacl, 342 FALSE); 343 if (!NT_SUCCESS(Status)) 344 { 345 goto Cleanup; 346 } 347 348 /* convert it back to a self-relative descriptor, find out how much 349 memory we need */ 350 Status = RtlAbsoluteToSelfRelativeSD(AbsSD, 351 NULL, 352 &RelSDSize); 353 if (Status != STATUS_BUFFER_TOO_SMALL) 354 { 355 goto Cleanup; 356 } 357 358 /* allocate enough memory for the new self-relative descriptor */ 359 NewRelSD = RtlpAllocateMemory(RelSDSize, 360 'dSeS'); 361 if (NewRelSD == NULL) 362 { 363 Status = STATUS_NO_MEMORY; 364 goto Cleanup; 365 } 366 367 /* convert the security descriptor to self-relative format */ 368 Status = RtlAbsoluteToSelfRelativeSD(AbsSD, 369 NewRelSD, 370 &RelSDSize); 371 if (Status == STATUS_BUFFER_TOO_SMALL) 372 { 373 goto Cleanup; 374 } 375 376 /* finally attempt to change the security information */ 377 Status = ZwSetSecurityObject(DirectoryHandle, 378 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, 379 NewRelSD); 380 381 Cleanup: 382 if (AdminSid != NULL) 383 { 384 RtlFreeSid(AdminSid); 385 } 386 387 if (LocalSystemSid != NULL) 388 { 389 RtlFreeSid(LocalSystemSid); 390 } 391 392 if (RelSD != NULL) 393 { 394 RtlpFreeMemory(RelSD, 395 'dSeS'); 396 } 397 398 if (NewRelSD != NULL) 399 { 400 RtlpFreeMemory(NewRelSD, 401 'dSeS'); 402 } 403 404 #ifdef _WIN64 405 if (AbsSDAllocated) 406 { 407 RtlpFreeMemory(AbsSD, 408 'dSeS'); 409 } 410 #endif 411 412 return Status; 413 } 414 415 _Must_inspect_result_ 416 static 417 NTSTATUS 418 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath, 419 IN PSECURITY_DESCRIPTOR SecurityDescriptor) 420 { 421 TOKEN_PRIVILEGES TokenPrivileges; 422 OBJECT_ATTRIBUTES ObjectAttributes; 423 SECURITY_DESCRIPTOR AbsSD; 424 PSID AdminSid = NULL; 425 IO_STATUS_BLOCK IoStatusBlock; 426 BOOLEAN TokenEnabled = FALSE; 427 HANDLE hToken = NULL; 428 HANDLE hDirectory = NULL; 429 NTSTATUS Status; 430 ULONG ReturnLength; 431 432 Status = ZwOpenProcessToken(NtCurrentProcess(), 433 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, 434 &hToken); 435 if (!NT_SUCCESS(Status)) 436 { 437 goto Cleanup; 438 } 439 440 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */ 441 TokenPrivileges.PrivilegeCount = 1; 442 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; 443 TokenPrivileges.Privileges[0].Luid.HighPart = 0; 444 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 445 Status = ZwAdjustPrivilegesToken(hToken, 446 FALSE, 447 &TokenPrivileges, 448 sizeof(TokenPrivileges), 449 &TokenPrivileges, 450 &ReturnLength); 451 if (!NT_SUCCESS(Status)) 452 { 453 goto Cleanup; 454 } 455 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0); 456 457 /* open the directory */ 458 InitializeObjectAttributes(&ObjectAttributes, 459 DirectoryPath, 460 0, 461 NULL, 462 SecurityDescriptor); 463 464 Status = ZwOpenFile(&hDirectory, 465 SYNCHRONIZE | WRITE_OWNER, 466 &ObjectAttributes, 467 &IoStatusBlock, 468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 469 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 470 if (!NT_SUCCESS(Status)) 471 { 472 goto Cleanup; 473 } 474 475 /* create the Administrators SID */ 476 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 477 2, 478 SECURITY_BUILTIN_DOMAIN_RID, 479 DOMAIN_ALIAS_RID_ADMINS, 480 0, 481 0, 482 0, 483 0, 484 0, 485 0, 486 &AdminSid); 487 if (!NT_SUCCESS(Status)) 488 { 489 goto Cleanup; 490 } 491 492 /* create the security descriptor */ 493 Status = RtlCreateSecurityDescriptor(&AbsSD, 494 SECURITY_DESCRIPTOR_REVISION); 495 if (!NT_SUCCESS(Status)) 496 { 497 goto Cleanup; 498 } 499 500 Status = RtlSetOwnerSecurityDescriptor(&AbsSD, 501 AdminSid, 502 FALSE); 503 if (!NT_SUCCESS(Status)) 504 { 505 goto Cleanup; 506 } 507 508 /* attempt to take ownership */ 509 Status = ZwSetSecurityObject(hDirectory, 510 OWNER_SECURITY_INFORMATION, 511 &AbsSD); 512 513 Cleanup: 514 if (TokenEnabled) 515 { 516 /* Disable privileges that we had to enable, whetever the result was. */ 517 NTSTATUS Status2 = ZwAdjustPrivilegesToken(hToken, 518 FALSE, 519 &TokenPrivileges, 520 0, 521 NULL, 522 NULL); 523 /* This must succeed */ 524 ASSERT(NT_SUCCESS(Status2)); 525 (void)Status2; 526 } 527 528 if (AdminSid != NULL) 529 { 530 RtlFreeSid(AdminSid); 531 } 532 533 if (hDirectory != NULL) 534 { 535 ZwClose(hDirectory); 536 } 537 538 if (hToken != NULL) 539 { 540 ZwClose(hToken); 541 } 542 543 return Status; 544 } 545 546 /* 547 * @implemented 548 */ 549 NTSTATUS 550 NTAPI 551 RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath) 552 { 553 OBJECT_ATTRIBUTES ObjectAttributes; 554 IO_STATUS_BLOCK IoStatusBlock; 555 HANDLE hDirectory; 556 UNICODE_STRING DirectoryName, NewPath; 557 ULONG PathLen; 558 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL; 559 PSID SystemSid = NULL; 560 BOOLEAN AddSep = FALSE; 561 NTSTATUS Status; 562 563 PAGED_CODE_RTL(); 564 565 RtlInitUnicodeString(&DirectoryName, 566 L"System Volume Information"); 567 568 PathLen = VolumeRootPath->Length + DirectoryName.Length; 569 570 /* make sure we don't overflow while appending the strings */ 571 if (PathLen > 0xFFFC) 572 { 573 return STATUS_INVALID_PARAMETER; 574 } 575 576 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\') 577 { 578 AddSep = TRUE; 579 PathLen += sizeof(WCHAR); 580 } 581 582 /* allocate the new string */ 583 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR); 584 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength, 585 TAG_USTR); 586 if (NewPath.Buffer == NULL) 587 { 588 return STATUS_INSUFFICIENT_RESOURCES; 589 } 590 591 /* create the new path string */ 592 NewPath.Length = VolumeRootPath->Length; 593 RtlCopyMemory(NewPath.Buffer, 594 VolumeRootPath->Buffer, 595 NewPath.Length); 596 if (AddSep) 597 { 598 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\'; 599 NewPath.Length += sizeof(WCHAR); 600 } 601 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)), 602 DirectoryName.Buffer, 603 DirectoryName.Length); 604 NewPath.Length += DirectoryName.Length; 605 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0'; 606 607 ASSERT(NewPath.Length == PathLen); 608 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR)); 609 610 /* create the security descriptor for the new directory */ 611 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor, 612 &SystemSid); 613 if (NT_SUCCESS(Status)) 614 { 615 /* create or open the directory */ 616 InitializeObjectAttributes(&ObjectAttributes, 617 &NewPath, 618 0, 619 NULL, 620 SecurityDescriptor); 621 622 Status = ZwCreateFile(&hDirectory, 623 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, 624 &ObjectAttributes, 625 &IoStatusBlock, 626 NULL, 627 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 628 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 629 FILE_OPEN_IF, 630 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 631 NULL, 632 0); 633 if (!NT_SUCCESS(Status)) 634 { 635 Status = RtlpSysVolTakeOwnership(&NewPath, 636 SecurityDescriptor); 637 638 if (NT_SUCCESS(Status)) 639 { 640 /* successfully took ownership, attempt to open it */ 641 Status = ZwCreateFile(&hDirectory, 642 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, 643 &ObjectAttributes, 644 &IoStatusBlock, 645 NULL, 646 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 647 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 648 FILE_OPEN_IF, 649 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 650 NULL, 651 0); 652 } 653 } 654 655 if (NT_SUCCESS(Status)) 656 { 657 /* check security now and adjust it if neccessary */ 658 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory, 659 SecurityDescriptor); 660 ZwClose(hDirectory); 661 } 662 663 /* free allocated memory */ 664 ASSERT(SecurityDescriptor != NULL); 665 ASSERT(SecurityDescriptor->Dacl != NULL); 666 667 RtlpFreeMemory(SecurityDescriptor->Dacl, 668 'cAeS'); 669 RtlpFreeMemory(SecurityDescriptor, 670 'dSeS'); 671 672 RtlFreeSid(SystemSid); 673 } 674 675 RtlpFreeStringMemory(NewPath.Buffer, 676 TAG_USTR); 677 return Status; 678 } 679 680 /* EOF */ 681