1 /* Copyright (c) Mark Harmstone 2016-17 2 * 3 * This file is part of WinBtrfs. 4 * 5 * WinBtrfs is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public Licence as published by 7 * the Free Software Foundation, either version 3 of the Licence, or 8 * (at your option) any later version. 9 * 10 * WinBtrfs is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public Licence for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public Licence 16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "btrfs_drv.h" 19 20 #define SEF_DACL_AUTO_INHERIT 0x01 21 #define SEF_SACL_AUTO_INHERIT 0x02 22 23 typedef struct { 24 UCHAR revision; 25 UCHAR elements; 26 UCHAR auth[6]; 27 uint32_t nums[8]; 28 } sid_header; 29 30 static sid_header sid_BA = { 1, 2, SECURITY_NT_AUTHORITY, {32, 544}}; // BUILTIN\Administrators 31 static sid_header sid_SY = { 1, 1, SECURITY_NT_AUTHORITY, {18}}; // NT AUTHORITY\SYSTEM 32 static sid_header sid_BU = { 1, 2, SECURITY_NT_AUTHORITY, {32, 545}}; // BUILTIN\Users 33 static sid_header sid_AU = { 1, 1, SECURITY_NT_AUTHORITY, {11}}; // NT AUTHORITY\Authenticated Users 34 35 typedef struct { 36 UCHAR flags; 37 ACCESS_MASK mask; 38 sid_header* sid; 39 } dacl; 40 41 static dacl def_dacls[] = { 42 { 0, FILE_ALL_ACCESS, &sid_BA }, 43 { OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, FILE_ALL_ACCESS, &sid_BA }, 44 { 0, FILE_ALL_ACCESS, &sid_SY }, 45 { OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, FILE_ALL_ACCESS, &sid_SY }, 46 { OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE, &sid_BU }, 47 { OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, &sid_AU }, 48 { 0, FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE, &sid_AU }, 49 // FIXME - Mandatory Label\High Mandatory Level:(OI)(NP)(IO)(NW) 50 { 0, 0, NULL } 51 }; 52 53 extern LIST_ENTRY uid_map_list, gid_map_list; 54 extern ERESOURCE mapping_lock; 55 56 void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t uid) { 57 unsigned int i, np; 58 uint8_t numdashes; 59 uint64_t val; 60 ULONG sidsize; 61 sid_header* sid; 62 uid_map* um; 63 64 if (sidstringlength < 4 || 65 sidstring[0] != 'S' || 66 sidstring[1] != '-' || 67 sidstring[2] != '1' || 68 sidstring[3] != '-') { 69 ERR("invalid SID\n"); 70 return; 71 } 72 73 sidstring = &sidstring[4]; 74 sidstringlength -= 4; 75 76 numdashes = 0; 77 for (i = 0; i < sidstringlength; i++) { 78 if (sidstring[i] == '-') { 79 numdashes++; 80 sidstring[i] = 0; 81 } 82 } 83 84 sidsize = 8 + (numdashes * 4); 85 sid = ExAllocatePoolWithTag(PagedPool, sidsize, ALLOC_TAG); 86 if (!sid) { 87 ERR("out of memory\n"); 88 return; 89 } 90 91 sid->revision = 0x01; 92 sid->elements = numdashes; 93 94 np = 0; 95 while (sidstringlength > 0) { 96 val = 0; 97 i = 0; 98 while (sidstring[i] != '-' && i < sidstringlength) { 99 if (sidstring[i] >= '0' && sidstring[i] <= '9') { 100 val *= 10; 101 val += sidstring[i] - '0'; 102 } else 103 break; 104 105 i++; 106 } 107 108 i++; 109 TRACE("val = %u, i = %u, ssl = %u\n", (uint32_t)val, i, sidstringlength); 110 111 if (np == 0) { 112 sid->auth[0] = (uint8_t)((val & 0xff0000000000) >> 40); 113 sid->auth[1] = (uint8_t)((val & 0xff00000000) >> 32); 114 sid->auth[2] = (uint8_t)((val & 0xff000000) >> 24); 115 sid->auth[3] = (uint8_t)((val & 0xff0000) >> 16); 116 sid->auth[4] = (uint8_t)((val & 0xff00) >> 8); 117 sid->auth[5] = val & 0xff; 118 } else { 119 sid->nums[np-1] = (uint32_t)val; 120 } 121 122 np++; 123 124 if (sidstringlength > i) { 125 sidstringlength -= i; 126 127 sidstring = &sidstring[i]; 128 } else 129 break; 130 } 131 132 um = ExAllocatePoolWithTag(PagedPool, sizeof(uid_map), ALLOC_TAG); 133 if (!um) { 134 ERR("out of memory\n"); 135 ExFreePool(sid); 136 return; 137 } 138 139 um->sid = sid; 140 um->uid = uid; 141 142 InsertTailList(&uid_map_list, &um->listentry); 143 } 144 145 void add_group_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t gid) { 146 unsigned int i, np; 147 uint8_t numdashes; 148 uint64_t val; 149 ULONG sidsize; 150 sid_header* sid; 151 gid_map* gm; 152 153 if (sidstringlength < 4 || sidstring[0] != 'S' || sidstring[1] != '-' || sidstring[2] != '1' || sidstring[3] != '-') { 154 ERR("invalid SID\n"); 155 return; 156 } 157 158 sidstring = &sidstring[4]; 159 sidstringlength -= 4; 160 161 numdashes = 0; 162 for (i = 0; i < sidstringlength; i++) { 163 if (sidstring[i] == '-') { 164 numdashes++; 165 sidstring[i] = 0; 166 } 167 } 168 169 sidsize = 8 + (numdashes * 4); 170 sid = ExAllocatePoolWithTag(PagedPool, sidsize, ALLOC_TAG); 171 if (!sid) { 172 ERR("out of memory\n"); 173 return; 174 } 175 176 sid->revision = 0x01; 177 sid->elements = numdashes; 178 179 np = 0; 180 while (sidstringlength > 0) { 181 val = 0; 182 i = 0; 183 while (sidstring[i] != '-' && i < sidstringlength) { 184 if (sidstring[i] >= '0' && sidstring[i] <= '9') { 185 val *= 10; 186 val += sidstring[i] - '0'; 187 } else 188 break; 189 190 i++; 191 } 192 193 i++; 194 TRACE("val = %u, i = %u, ssl = %u\n", (uint32_t)val, i, sidstringlength); 195 196 if (np == 0) { 197 sid->auth[0] = (uint8_t)((val & 0xff0000000000) >> 40); 198 sid->auth[1] = (uint8_t)((val & 0xff00000000) >> 32); 199 sid->auth[2] = (uint8_t)((val & 0xff000000) >> 24); 200 sid->auth[3] = (uint8_t)((val & 0xff0000) >> 16); 201 sid->auth[4] = (uint8_t)((val & 0xff00) >> 8); 202 sid->auth[5] = val & 0xff; 203 } else 204 sid->nums[np-1] = (uint32_t)val; 205 206 np++; 207 208 if (sidstringlength > i) { 209 sidstringlength -= i; 210 211 sidstring = &sidstring[i]; 212 } else 213 break; 214 } 215 216 gm = ExAllocatePoolWithTag(PagedPool, sizeof(gid_map), ALLOC_TAG); 217 if (!gm) { 218 ERR("out of memory\n"); 219 ExFreePool(sid); 220 return; 221 } 222 223 gm->sid = sid; 224 gm->gid = gid; 225 226 InsertTailList(&gid_map_list, &gm->listentry); 227 } 228 229 NTSTATUS uid_to_sid(uint32_t uid, PSID* sid) { 230 LIST_ENTRY* le; 231 sid_header* sh; 232 UCHAR els; 233 234 ExAcquireResourceSharedLite(&mapping_lock, true); 235 236 le = uid_map_list.Flink; 237 while (le != &uid_map_list) { 238 uid_map* um = CONTAINING_RECORD(le, uid_map, listentry); 239 240 if (um->uid == uid) { 241 *sid = ExAllocatePoolWithTag(PagedPool, RtlLengthSid(um->sid), ALLOC_TAG); 242 if (!*sid) { 243 ERR("out of memory\n"); 244 ExReleaseResourceLite(&mapping_lock); 245 return STATUS_INSUFFICIENT_RESOURCES; 246 } 247 248 RtlCopyMemory(*sid, um->sid, RtlLengthSid(um->sid)); 249 ExReleaseResourceLite(&mapping_lock); 250 return STATUS_SUCCESS; 251 } 252 253 le = le->Flink; 254 } 255 256 ExReleaseResourceLite(&mapping_lock); 257 258 if (uid == 0) { // root 259 // FIXME - find actual Administrator account, rather than SYSTEM (S-1-5-18) 260 // (of form S-1-5-21-...-500) 261 262 els = 1; 263 264 sh = ExAllocatePoolWithTag(PagedPool, sizeof(sid_header) + ((els - 1) * sizeof(uint32_t)), ALLOC_TAG); 265 if (!sh) { 266 ERR("out of memory\n"); 267 *sid = NULL; 268 return STATUS_INSUFFICIENT_RESOURCES; 269 } 270 271 sh->revision = 1; 272 sh->elements = els; 273 274 sh->auth[0] = 0; 275 sh->auth[1] = 0; 276 sh->auth[2] = 0; 277 sh->auth[3] = 0; 278 sh->auth[4] = 0; 279 sh->auth[5] = 5; 280 281 sh->nums[0] = 18; 282 } else { 283 // fallback to S-1-22-1-X, Samba's SID scheme 284 sh = ExAllocatePoolWithTag(PagedPool, sizeof(sid_header), ALLOC_TAG); 285 if (!sh) { 286 ERR("out of memory\n"); 287 *sid = NULL; 288 return STATUS_INSUFFICIENT_RESOURCES; 289 } 290 291 sh->revision = 1; 292 sh->elements = 2; 293 294 sh->auth[0] = 0; 295 sh->auth[1] = 0; 296 sh->auth[2] = 0; 297 sh->auth[3] = 0; 298 sh->auth[4] = 0; 299 sh->auth[5] = 22; 300 301 sh->nums[0] = 1; 302 sh->nums[1] = uid; 303 } 304 305 *sid = sh; 306 307 return STATUS_SUCCESS; 308 } 309 310 uint32_t sid_to_uid(PSID sid) { 311 LIST_ENTRY* le; 312 sid_header* sh = sid; 313 314 ExAcquireResourceSharedLite(&mapping_lock, true); 315 316 le = uid_map_list.Flink; 317 while (le != &uid_map_list) { 318 uid_map* um = CONTAINING_RECORD(le, uid_map, listentry); 319 320 if (RtlEqualSid(sid, um->sid)) { 321 ExReleaseResourceLite(&mapping_lock); 322 return um->uid; 323 } 324 325 le = le->Flink; 326 } 327 328 ExReleaseResourceLite(&mapping_lock); 329 330 if (RtlEqualSid(sid, &sid_SY)) 331 return 0; // root 332 333 // Samba's SID scheme: S-1-22-1-X 334 if (sh->revision == 1 && sh->elements == 2 && sh->auth[0] == 0 && sh->auth[1] == 0 && sh->auth[2] == 0 && sh->auth[3] == 0 && 335 sh->auth[4] == 0 && sh->auth[5] == 22 && sh->nums[0] == 1) 336 return sh->nums[1]; 337 338 return UID_NOBODY; 339 } 340 341 static void gid_to_sid(uint32_t gid, PSID* sid) { 342 sid_header* sh; 343 UCHAR els; 344 345 // FIXME - do this properly? 346 347 // fallback to S-1-22-2-X, Samba's SID scheme 348 els = 2; 349 sh = ExAllocatePoolWithTag(PagedPool, sizeof(sid_header) + ((els - 1) * sizeof(uint32_t)), ALLOC_TAG); 350 if (!sh) { 351 ERR("out of memory\n"); 352 *sid = NULL; 353 return; 354 } 355 356 sh->revision = 1; 357 sh->elements = els; 358 359 sh->auth[0] = 0; 360 sh->auth[1] = 0; 361 sh->auth[2] = 0; 362 sh->auth[3] = 0; 363 sh->auth[4] = 0; 364 sh->auth[5] = 22; 365 366 sh->nums[0] = 2; 367 sh->nums[1] = gid; 368 369 *sid = sh; 370 } 371 372 static ACL* load_default_acl() { 373 uint16_t size, i; 374 ACL* acl; 375 ACCESS_ALLOWED_ACE* aaa; 376 377 size = sizeof(ACL); 378 i = 0; 379 while (def_dacls[i].sid) { 380 size += sizeof(ACCESS_ALLOWED_ACE); 381 size += 8 + (def_dacls[i].sid->elements * sizeof(uint32_t)) - sizeof(ULONG); 382 i++; 383 } 384 385 acl = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG); 386 if (!acl) { 387 ERR("out of memory\n"); 388 return NULL; 389 } 390 391 acl->AclRevision = ACL_REVISION; 392 acl->Sbz1 = 0; 393 acl->AclSize = size; 394 acl->AceCount = i; 395 acl->Sbz2 = 0; 396 397 aaa = (ACCESS_ALLOWED_ACE*)&acl[1]; 398 i = 0; 399 while (def_dacls[i].sid) { 400 aaa->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; 401 aaa->Header.AceFlags = def_dacls[i].flags; 402 aaa->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + 8 + (def_dacls[i].sid->elements * sizeof(uint32_t)); 403 aaa->Mask = def_dacls[i].mask; 404 405 RtlCopyMemory(&aaa->SidStart, def_dacls[i].sid, 8 + (def_dacls[i].sid->elements * sizeof(uint32_t))); 406 407 aaa = (ACCESS_ALLOWED_ACE*)((uint8_t*)aaa + aaa->Header.AceSize); 408 409 i++; 410 } 411 412 return acl; 413 } 414 415 static void get_top_level_sd(fcb* fcb) { 416 NTSTATUS Status; 417 SECURITY_DESCRIPTOR sd; 418 ULONG buflen; 419 ACL* acl = NULL; 420 PSID usersid = NULL, groupsid = NULL; 421 422 Status = RtlCreateSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 423 424 if (!NT_SUCCESS(Status)) { 425 ERR("RtlCreateSecurityDescriptor returned %08x\n", Status); 426 goto end; 427 } 428 429 Status = uid_to_sid(fcb->inode_item.st_uid, &usersid); 430 if (!NT_SUCCESS(Status)) { 431 ERR("uid_to_sid returned %08x\n", Status); 432 goto end; 433 } 434 435 RtlSetOwnerSecurityDescriptor(&sd, usersid, false); 436 437 if (!NT_SUCCESS(Status)) { 438 ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status); 439 goto end; 440 } 441 442 gid_to_sid(fcb->inode_item.st_gid, &groupsid); 443 if (!groupsid) { 444 ERR("out of memory\n"); 445 Status = STATUS_INSUFFICIENT_RESOURCES; 446 goto end; 447 } 448 449 RtlSetGroupSecurityDescriptor(&sd, groupsid, false); 450 451 if (!NT_SUCCESS(Status)) { 452 ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status); 453 goto end; 454 } 455 456 acl = load_default_acl(); 457 458 if (!acl) { 459 ERR("out of memory\n"); 460 goto end; 461 } 462 463 Status = RtlSetDaclSecurityDescriptor(&sd, true, acl, false); 464 465 if (!NT_SUCCESS(Status)) { 466 ERR("RtlSetDaclSecurityDescriptor returned %08x\n", Status); 467 goto end; 468 } 469 470 // FIXME - SACL_SECURITY_INFORMATION 471 472 buflen = 0; 473 474 // get sd size 475 Status = RtlAbsoluteToSelfRelativeSD(&sd, NULL, &buflen); 476 if (Status != STATUS_SUCCESS && Status != STATUS_BUFFER_TOO_SMALL) { 477 ERR("RtlAbsoluteToSelfRelativeSD 1 returned %08x\n", Status); 478 goto end; 479 } 480 481 if (buflen == 0 || Status == STATUS_SUCCESS) { 482 TRACE("RtlAbsoluteToSelfRelativeSD said SD is zero-length\n"); 483 goto end; 484 } 485 486 fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); 487 if (!fcb->sd) { 488 ERR("out of memory\n"); 489 Status = STATUS_INSUFFICIENT_RESOURCES; 490 goto end; 491 } 492 493 Status = RtlAbsoluteToSelfRelativeSD(&sd, fcb->sd, &buflen); 494 495 if (!NT_SUCCESS(Status)) { 496 ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status); 497 goto end; 498 } 499 500 end: 501 if (acl) 502 ExFreePool(acl); 503 504 if (usersid) 505 ExFreePool(usersid); 506 507 if (groupsid) 508 ExFreePool(groupsid); 509 } 510 511 void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr, PIRP Irp) { 512 NTSTATUS Status; 513 PSID usersid = NULL, groupsid = NULL; 514 SECURITY_SUBJECT_CONTEXT subjcont; 515 ULONG buflen; 516 517 if (look_for_xattr && get_xattr(fcb->Vcb, fcb->subvol, fcb->inode, EA_NTACL, EA_NTACL_HASH, (uint8_t**)&fcb->sd, (uint16_t*)&buflen, Irp)) 518 return; 519 520 if (!parent) { 521 get_top_level_sd(fcb); 522 return; 523 } 524 525 SeCaptureSubjectContext(&subjcont); 526 527 Status = SeAssignSecurityEx(parent->sd, NULL, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY, SEF_DACL_AUTO_INHERIT, 528 &subjcont, IoGetFileObjectGenericMapping(), PagedPool); 529 if (!NT_SUCCESS(Status)) { 530 ERR("SeAssignSecurityEx returned %08x\n", Status); 531 } 532 533 Status = uid_to_sid(fcb->inode_item.st_uid, &usersid); 534 if (!NT_SUCCESS(Status)) { 535 ERR("uid_to_sid returned %08x\n", Status); 536 return; 537 } 538 539 RtlSetOwnerSecurityDescriptor(&fcb->sd, usersid, false); 540 541 gid_to_sid(fcb->inode_item.st_gid, &groupsid); 542 if (!groupsid) { 543 ERR("out of memory\n"); 544 return; 545 } 546 547 RtlSetGroupSecurityDescriptor(&fcb->sd, groupsid, false); 548 549 ExFreePool(usersid); 550 ExFreePool(groupsid); 551 } 552 553 static NTSTATUS get_file_security(PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* relsd, ULONG* buflen, SECURITY_INFORMATION flags) { 554 NTSTATUS Status; 555 fcb* fcb = FileObject->FsContext; 556 ccb* ccb = FileObject->FsContext2; 557 file_ref* fileref = ccb ? ccb->fileref : NULL; 558 559 if (fcb->ads) { 560 if (fileref && fileref->parent) 561 fcb = fileref->parent->fcb; 562 else { 563 ERR("could not get parent fcb for stream\n"); 564 return STATUS_INTERNAL_ERROR; 565 } 566 } 567 568 // Why (void**)? Is this a bug in mingw? 569 Status = SeQuerySecurityDescriptorInfo(&flags, relsd, buflen, (void**)&fcb->sd); 570 571 if (Status == STATUS_BUFFER_TOO_SMALL) 572 TRACE("SeQuerySecurityDescriptorInfo returned %08x\n", Status); 573 else if (!NT_SUCCESS(Status)) 574 ERR("SeQuerySecurityDescriptorInfo returned %08x\n", Status); 575 576 return Status; 577 } 578 579 _Dispatch_type_(IRP_MJ_QUERY_SECURITY) 580 _Function_class_(DRIVER_DISPATCH) 581 NTSTATUS __stdcall drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 582 NTSTATUS Status; 583 SECURITY_DESCRIPTOR* sd; 584 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 585 device_extension* Vcb = DeviceObject->DeviceExtension; 586 ULONG buflen; 587 bool top_level; 588 PFILE_OBJECT FileObject = IrpSp->FileObject; 589 ccb* ccb = FileObject ? FileObject->FsContext2 : NULL; 590 591 FsRtlEnterFileSystem(); 592 593 TRACE("query security\n"); 594 595 top_level = is_top_level(Irp); 596 597 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 598 Status = vol_query_security(DeviceObject, Irp); 599 goto end; 600 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 601 Status = STATUS_INVALID_PARAMETER; 602 goto end; 603 } 604 605 if (!ccb) { 606 ERR("no ccb\n"); 607 Status = STATUS_INVALID_PARAMETER; 608 goto end; 609 } 610 611 if (Irp->RequestorMode == UserMode && !(ccb->access & READ_CONTROL)) { 612 WARN("insufficient permissions\n"); 613 Status = STATUS_ACCESS_DENIED; 614 goto end; 615 } 616 617 Status = STATUS_SUCCESS; 618 619 Irp->IoStatus.Information = 0; 620 621 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) 622 TRACE("OWNER_SECURITY_INFORMATION\n"); 623 624 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) 625 TRACE("GROUP_SECURITY_INFORMATION\n"); 626 627 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & DACL_SECURITY_INFORMATION) 628 TRACE("DACL_SECURITY_INFORMATION\n"); 629 630 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & SACL_SECURITY_INFORMATION) 631 TRACE("SACL_SECURITY_INFORMATION\n"); 632 633 TRACE("length = %u\n", IrpSp->Parameters.QuerySecurity.Length); 634 635 sd = map_user_buffer(Irp, NormalPagePriority); 636 TRACE("sd = %p\n", sd); 637 638 if (Irp->MdlAddress && !sd) { 639 ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); 640 Status = STATUS_INSUFFICIENT_RESOURCES; 641 goto end; 642 } 643 644 buflen = IrpSp->Parameters.QuerySecurity.Length; 645 646 Status = get_file_security(IrpSp->FileObject, sd, &buflen, IrpSp->Parameters.QuerySecurity.SecurityInformation); 647 648 if (NT_SUCCESS(Status)) 649 Irp->IoStatus.Information = IrpSp->Parameters.QuerySecurity.Length; 650 else if (Status == STATUS_BUFFER_TOO_SMALL) { 651 Irp->IoStatus.Information = buflen; 652 Status = STATUS_BUFFER_OVERFLOW; 653 } else 654 Irp->IoStatus.Information = 0; 655 656 end: 657 TRACE("Irp->IoStatus.Information = %u\n", Irp->IoStatus.Information); 658 659 Irp->IoStatus.Status = Status; 660 661 IoCompleteRequest(Irp, IO_NO_INCREMENT); 662 663 if (top_level) 664 IoSetTopLevelIrp(NULL); 665 666 TRACE("returning %08x\n", Status); 667 668 FsRtlExitFileSystem(); 669 670 return Status; 671 } 672 673 static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* sd, PSECURITY_INFORMATION flags, PIRP Irp) { 674 NTSTATUS Status; 675 fcb* fcb = FileObject->FsContext; 676 ccb* ccb = FileObject->FsContext2; 677 file_ref* fileref = ccb ? ccb->fileref : NULL; 678 SECURITY_DESCRIPTOR* oldsd; 679 LARGE_INTEGER time; 680 BTRFS_TIME now; 681 682 TRACE("(%p, %p, %p, %x)\n", Vcb, FileObject, sd, *flags); 683 684 if (Vcb->readonly) 685 return STATUS_MEDIA_WRITE_PROTECTED; 686 687 if (fcb->ads) { 688 if (fileref && fileref->parent) 689 fcb = fileref->parent->fcb; 690 else { 691 ERR("could not find parent fcb for stream\n"); 692 return STATUS_INTERNAL_ERROR; 693 } 694 } 695 696 if (!fcb || !ccb) 697 return STATUS_INVALID_PARAMETER; 698 699 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); 700 701 if (is_subvol_readonly(fcb->subvol, Irp)) { 702 Status = STATUS_ACCESS_DENIED; 703 goto end; 704 } 705 706 oldsd = fcb->sd; 707 708 Status = SeSetSecurityDescriptorInfo(NULL, flags, sd, (void**)&fcb->sd, PagedPool, IoGetFileObjectGenericMapping()); 709 710 if (!NT_SUCCESS(Status)) { 711 ERR("SeSetSecurityDescriptorInfo returned %08x\n", Status); 712 goto end; 713 } 714 715 ExFreePool(oldsd); 716 717 KeQuerySystemTime(&time); 718 win_time_to_unix(time, &now); 719 720 fcb->inode_item.transid = Vcb->superblock.generation; 721 722 if (!ccb->user_set_change_time) 723 fcb->inode_item.st_ctime = now; 724 725 fcb->inode_item.sequence++; 726 727 fcb->sd_dirty = true; 728 fcb->sd_deleted = false; 729 fcb->inode_item_changed = true; 730 731 fcb->subvol->root_item.ctransid = Vcb->superblock.generation; 732 fcb->subvol->root_item.ctime = now; 733 734 mark_fcb_dirty(fcb); 735 736 send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL); 737 738 end: 739 ExReleaseResourceLite(fcb->Header.Resource); 740 741 return Status; 742 } 743 744 _Dispatch_type_(IRP_MJ_SET_SECURITY) 745 _Function_class_(DRIVER_DISPATCH) 746 NTSTATUS __stdcall drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 747 NTSTATUS Status; 748 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 749 PFILE_OBJECT FileObject = IrpSp->FileObject; 750 ccb* ccb = FileObject ? FileObject->FsContext2 : NULL; 751 device_extension* Vcb = DeviceObject->DeviceExtension; 752 ULONG access_req = 0; 753 bool top_level; 754 755 FsRtlEnterFileSystem(); 756 757 TRACE("set security\n"); 758 759 top_level = is_top_level(Irp); 760 761 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 762 Status = vol_set_security(DeviceObject, Irp); 763 goto end; 764 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 765 Status = STATUS_INVALID_PARAMETER; 766 goto end; 767 } 768 769 if (!ccb) { 770 ERR("no ccb\n"); 771 Status = STATUS_INVALID_PARAMETER; 772 goto end; 773 } 774 775 Status = STATUS_SUCCESS; 776 777 Irp->IoStatus.Information = 0; 778 779 if (IrpSp->Parameters.SetSecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) { 780 TRACE("OWNER_SECURITY_INFORMATION\n"); 781 access_req |= WRITE_OWNER; 782 } 783 784 if (IrpSp->Parameters.SetSecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) { 785 TRACE("GROUP_SECURITY_INFORMATION\n"); 786 access_req |= WRITE_OWNER; 787 } 788 789 if (IrpSp->Parameters.SetSecurity.SecurityInformation & DACL_SECURITY_INFORMATION) { 790 TRACE("DACL_SECURITY_INFORMATION\n"); 791 access_req |= WRITE_DAC; 792 } 793 794 if (IrpSp->Parameters.SetSecurity.SecurityInformation & SACL_SECURITY_INFORMATION) { 795 TRACE("SACL_SECURITY_INFORMATION\n"); 796 access_req |= ACCESS_SYSTEM_SECURITY; 797 } 798 799 if (Irp->RequestorMode == UserMode && (ccb->access & access_req) != access_req) { 800 Status = STATUS_ACCESS_DENIED; 801 WARN("insufficient privileges\n"); 802 goto end; 803 } 804 805 Status = set_file_security(DeviceObject->DeviceExtension, FileObject, IrpSp->Parameters.SetSecurity.SecurityDescriptor, 806 &IrpSp->Parameters.SetSecurity.SecurityInformation, Irp); 807 808 end: 809 Irp->IoStatus.Status = Status; 810 811 IoCompleteRequest(Irp, IO_NO_INCREMENT); 812 813 TRACE("returning %08x\n", Status); 814 815 if (top_level) 816 IoSetTopLevelIrp(NULL); 817 818 FsRtlExitFileSystem(); 819 820 return Status; 821 } 822 823 static bool search_for_gid(fcb* fcb, PSID sid) { 824 LIST_ENTRY* le; 825 826 le = gid_map_list.Flink; 827 while (le != &gid_map_list) { 828 gid_map* gm = CONTAINING_RECORD(le, gid_map, listentry); 829 830 if (RtlEqualSid(sid, gm->sid)) { 831 fcb->inode_item.st_gid = gm->gid; 832 return true; 833 } 834 835 le = le->Flink; 836 } 837 838 return false; 839 } 840 841 void find_gid(struct _fcb* fcb, struct _fcb* parfcb, PSECURITY_SUBJECT_CONTEXT subjcont) { 842 NTSTATUS Status; 843 TOKEN_OWNER* to; 844 TOKEN_PRIMARY_GROUP* tpg; 845 TOKEN_GROUPS* tg; 846 847 if (parfcb && parfcb->inode_item.st_mode & S_ISGID) { 848 fcb->inode_item.st_gid = parfcb->inode_item.st_gid; 849 return; 850 } 851 852 ExAcquireResourceSharedLite(&mapping_lock, true); 853 854 if (!subjcont || !subjcont->PrimaryToken || IsListEmpty(&gid_map_list)) { 855 ExReleaseResourceLite(&mapping_lock); 856 return; 857 } 858 859 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenOwner, (void**)&to); 860 if (!NT_SUCCESS(Status)) 861 ERR("SeQueryInformationToken returned %08x\n", Status); 862 else { 863 if (search_for_gid(fcb, to->Owner)) { 864 ExReleaseResourceLite(&mapping_lock); 865 ExFreePool(to); 866 return; 867 } 868 869 ExFreePool(to); 870 } 871 872 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenPrimaryGroup, (void**)&tpg); 873 if (!NT_SUCCESS(Status)) 874 ERR("SeQueryInformationToken returned %08x\n", Status); 875 else { 876 if (search_for_gid(fcb, tpg->PrimaryGroup)) { 877 ExReleaseResourceLite(&mapping_lock); 878 ExFreePool(tpg); 879 return; 880 } 881 882 ExFreePool(tpg); 883 } 884 885 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenGroups, (void**)&tg); 886 if (!NT_SUCCESS(Status)) 887 ERR("SeQueryInformationToken returned %08x\n", Status); 888 else { 889 ULONG i; 890 891 for (i = 0; i < tg->GroupCount; i++) { 892 if (search_for_gid(fcb, tg->Groups[i].Sid)) { 893 ExReleaseResourceLite(&mapping_lock); 894 ExFreePool(tg); 895 return; 896 } 897 } 898 899 ExFreePool(tg); 900 } 901 902 ExReleaseResourceLite(&mapping_lock); 903 } 904 905 NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as) { 906 NTSTATUS Status; 907 PSID owner; 908 BOOLEAN defaulted; 909 910 Status = SeAssignSecurityEx(parfileref ? parfileref->fcb->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY, 911 SEF_SACL_AUTO_INHERIT, &as->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool); 912 913 if (!NT_SUCCESS(Status)) { 914 ERR("SeAssignSecurityEx returned %08x\n", Status); 915 return Status; 916 } 917 918 Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted); 919 if (!NT_SUCCESS(Status)) { 920 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status); 921 fcb->inode_item.st_uid = UID_NOBODY; 922 } else { 923 fcb->inode_item.st_uid = sid_to_uid(owner); 924 } 925 926 find_gid(fcb, parfileref ? parfileref->fcb : NULL, &as->SubjectSecurityContext); 927 928 return STATUS_SUCCESS; 929 } 930