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 static NTSTATUS 416 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath, 417 IN PSECURITY_DESCRIPTOR SecurityDescriptor) 418 { 419 TOKEN_PRIVILEGES TokenPrivileges; 420 OBJECT_ATTRIBUTES ObjectAttributes; 421 SECURITY_DESCRIPTOR AbsSD; 422 PSID AdminSid = NULL; 423 IO_STATUS_BLOCK IoStatusBlock; 424 BOOLEAN TokenEnabled = FALSE; 425 HANDLE hToken = NULL; 426 HANDLE hDirectory = NULL; 427 NTSTATUS Status; 428 ULONG ReturnLength; 429 430 Status = ZwOpenProcessToken(NtCurrentProcess(), 431 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, 432 &hToken); 433 if (!NT_SUCCESS(Status)) 434 { 435 goto Cleanup; 436 } 437 438 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */ 439 TokenPrivileges.PrivilegeCount = 1; 440 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE; 441 TokenPrivileges.Privileges[0].Luid.HighPart = 0; 442 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 443 Status = ZwAdjustPrivilegesToken(hToken, 444 FALSE, 445 &TokenPrivileges, 446 sizeof(TokenPrivileges), 447 &TokenPrivileges, 448 &ReturnLength); 449 if (!NT_SUCCESS(Status)) 450 { 451 goto Cleanup; 452 } 453 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0); 454 455 /* open the directory */ 456 InitializeObjectAttributes(&ObjectAttributes, 457 DirectoryPath, 458 0, 459 NULL, 460 SecurityDescriptor); 461 462 Status = ZwOpenFile(&hDirectory, 463 SYNCHRONIZE | WRITE_OWNER, 464 &ObjectAttributes, 465 &IoStatusBlock, 466 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 467 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT); 468 if (!NT_SUCCESS(Status)) 469 { 470 goto Cleanup; 471 } 472 473 /* create the Administrators SID */ 474 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority, 475 2, 476 SECURITY_BUILTIN_DOMAIN_RID, 477 DOMAIN_ALIAS_RID_ADMINS, 478 0, 479 0, 480 0, 481 0, 482 0, 483 0, 484 &AdminSid); 485 if (!NT_SUCCESS(Status)) 486 { 487 goto Cleanup; 488 } 489 490 /* create the security descriptor */ 491 Status = RtlCreateSecurityDescriptor(&AbsSD, 492 SECURITY_DESCRIPTOR_REVISION); 493 if (!NT_SUCCESS(Status)) 494 { 495 goto Cleanup; 496 } 497 498 Status = RtlSetOwnerSecurityDescriptor(&AbsSD, 499 AdminSid, 500 FALSE); 501 if (!NT_SUCCESS(Status)) 502 { 503 goto Cleanup; 504 } 505 506 /* attempt to take ownership */ 507 Status = ZwSetSecurityObject(hDirectory, 508 OWNER_SECURITY_INFORMATION, 509 &AbsSD); 510 511 Cleanup: 512 if (TokenEnabled) 513 { 514 ZwAdjustPrivilegesToken(hToken, 515 FALSE, 516 &TokenPrivileges, 517 0, 518 NULL, 519 NULL); 520 } 521 522 if (AdminSid != NULL) 523 { 524 RtlFreeSid(AdminSid); 525 } 526 527 if (hDirectory != NULL) 528 { 529 ZwClose(hDirectory); 530 } 531 532 if (hToken != NULL) 533 { 534 ZwClose(hToken); 535 } 536 537 return Status; 538 } 539 540 /* 541 * @implemented 542 */ 543 NTSTATUS 544 NTAPI 545 RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath) 546 { 547 OBJECT_ATTRIBUTES ObjectAttributes; 548 IO_STATUS_BLOCK IoStatusBlock; 549 HANDLE hDirectory; 550 UNICODE_STRING DirectoryName, NewPath; 551 ULONG PathLen; 552 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL; 553 PSID SystemSid = NULL; 554 BOOLEAN AddSep = FALSE; 555 NTSTATUS Status; 556 557 PAGED_CODE_RTL(); 558 559 RtlInitUnicodeString(&DirectoryName, 560 L"System Volume Information"); 561 562 PathLen = VolumeRootPath->Length + DirectoryName.Length; 563 564 /* make sure we don't overflow while appending the strings */ 565 if (PathLen > 0xFFFC) 566 { 567 return STATUS_INVALID_PARAMETER; 568 } 569 570 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\') 571 { 572 AddSep = TRUE; 573 PathLen += sizeof(WCHAR); 574 } 575 576 /* allocate the new string */ 577 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR); 578 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength, 579 TAG_USTR); 580 if (NewPath.Buffer == NULL) 581 { 582 return STATUS_INSUFFICIENT_RESOURCES; 583 } 584 585 /* create the new path string */ 586 NewPath.Length = VolumeRootPath->Length; 587 RtlCopyMemory(NewPath.Buffer, 588 VolumeRootPath->Buffer, 589 NewPath.Length); 590 if (AddSep) 591 { 592 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\'; 593 NewPath.Length += sizeof(WCHAR); 594 } 595 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)), 596 DirectoryName.Buffer, 597 DirectoryName.Length); 598 NewPath.Length += DirectoryName.Length; 599 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0'; 600 601 ASSERT(NewPath.Length == PathLen); 602 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR)); 603 604 /* create the security descriptor for the new directory */ 605 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor, 606 &SystemSid); 607 if (NT_SUCCESS(Status)) 608 { 609 /* create or open the directory */ 610 InitializeObjectAttributes(&ObjectAttributes, 611 &NewPath, 612 0, 613 NULL, 614 SecurityDescriptor); 615 616 Status = ZwCreateFile(&hDirectory, 617 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, 618 &ObjectAttributes, 619 &IoStatusBlock, 620 NULL, 621 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 622 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 623 FILE_OPEN_IF, 624 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 625 NULL, 626 0); 627 if (!NT_SUCCESS(Status)) 628 { 629 Status = RtlpSysVolTakeOwnership(&NewPath, 630 SecurityDescriptor); 631 632 if (NT_SUCCESS(Status)) 633 { 634 /* successfully took ownership, attempt to open it */ 635 Status = ZwCreateFile(&hDirectory, 636 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL, 637 &ObjectAttributes, 638 &IoStatusBlock, 639 NULL, 640 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, 641 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 642 FILE_OPEN_IF, 643 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, 644 NULL, 645 0); 646 } 647 } 648 649 if (NT_SUCCESS(Status)) 650 { 651 /* check security now and adjust it if neccessary */ 652 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory, 653 SecurityDescriptor); 654 ZwClose(hDirectory); 655 } 656 657 /* free allocated memory */ 658 ASSERT(SecurityDescriptor != NULL); 659 ASSERT(SecurityDescriptor->Dacl != NULL); 660 661 RtlpFreeMemory(SecurityDescriptor->Dacl, 662 'cAeS'); 663 RtlpFreeMemory(SecurityDescriptor, 664 'dSeS'); 665 666 RtlFreeSid(SystemSid); 667 } 668 669 RtlpFreeStringMemory(NewPath.Buffer, 670 TAG_USTR); 671 return Status; 672 } 673 674 /* EOF */ 675