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 (i < sidstringlength && sidstring[i] != '-') { 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 = %lu\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 (i < sidstringlength && sidstring[i] != '-') { 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 = %lu\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 %08lx\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 %08lx\n", Status); 432 goto end; 433 } 434 435 Status = RtlSetOwnerSecurityDescriptor(&sd, usersid, false); 436 437 if (!NT_SUCCESS(Status)) { 438 ERR("RtlSetOwnerSecurityDescriptor returned %08lx\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 goto end; 446 } 447 448 Status = RtlSetGroupSecurityDescriptor(&sd, groupsid, false); 449 450 if (!NT_SUCCESS(Status)) { 451 ERR("RtlSetGroupSecurityDescriptor returned %08lx\n", Status); 452 goto end; 453 } 454 455 acl = load_default_acl(); 456 457 if (!acl) { 458 ERR("out of memory\n"); 459 goto end; 460 } 461 462 Status = RtlSetDaclSecurityDescriptor(&sd, true, acl, false); 463 464 if (!NT_SUCCESS(Status)) { 465 ERR("RtlSetDaclSecurityDescriptor returned %08lx\n", Status); 466 goto end; 467 } 468 469 // FIXME - SACL_SECURITY_INFORMATION 470 471 buflen = 0; 472 473 // get sd size 474 Status = RtlAbsoluteToSelfRelativeSD(&sd, NULL, &buflen); 475 if (Status != STATUS_SUCCESS && Status != STATUS_BUFFER_TOO_SMALL) { 476 ERR("RtlAbsoluteToSelfRelativeSD 1 returned %08lx\n", Status); 477 goto end; 478 } 479 480 if (buflen == 0 || Status == STATUS_SUCCESS) { 481 TRACE("RtlAbsoluteToSelfRelativeSD said SD is zero-length\n"); 482 goto end; 483 } 484 485 fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); 486 if (!fcb->sd) { 487 ERR("out of memory\n"); 488 goto end; 489 } 490 491 Status = RtlAbsoluteToSelfRelativeSD(&sd, fcb->sd, &buflen); 492 493 if (!NT_SUCCESS(Status)) { 494 ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08lx\n", Status); 495 ExFreePool(fcb->sd); 496 fcb->sd = NULL; 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 PSECURITY_DESCRIPTOR* abssd; 517 PSECURITY_DESCRIPTOR newsd; 518 PACL dacl, sacl; 519 PSID owner, group; 520 ULONG abssdlen = 0, dacllen = 0, sacllen = 0, ownerlen = 0, grouplen = 0; 521 uint8_t* buf; 522 523 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)) 524 return; 525 526 if (!parent) { 527 get_top_level_sd(fcb); 528 return; 529 } 530 531 SeCaptureSubjectContext(&subjcont); 532 533 Status = SeAssignSecurityEx(parent->sd, NULL, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY, SEF_DACL_AUTO_INHERIT, 534 &subjcont, IoGetFileObjectGenericMapping(), PagedPool); 535 if (!NT_SUCCESS(Status)) { 536 ERR("SeAssignSecurityEx returned %08lx\n", Status); 537 return; 538 } 539 540 Status = RtlSelfRelativeToAbsoluteSD(fcb->sd, NULL, &abssdlen, NULL, &dacllen, NULL, &sacllen, NULL, &ownerlen, 541 NULL, &grouplen); 542 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) { 543 ERR("RtlSelfRelativeToAbsoluteSD returned %08lx\n", Status); 544 return; 545 } 546 547 if (abssdlen + dacllen + sacllen + ownerlen + grouplen == 0) { 548 ERR("RtlSelfRelativeToAbsoluteSD returned zero lengths\n"); 549 return; 550 } 551 552 buf = (uint8_t*)ExAllocatePoolWithTag(PagedPool, abssdlen + dacllen + sacllen + ownerlen + grouplen, ALLOC_TAG); 553 if (!buf) { 554 ERR("out of memory\n"); 555 return; 556 } 557 558 abssd = (PSECURITY_DESCRIPTOR)buf; 559 dacl = (PACL)(buf + abssdlen); 560 sacl = (PACL)(buf + abssdlen + dacllen); 561 owner = (PSID)(buf + abssdlen + dacllen + sacllen); 562 group = (PSID)(buf + abssdlen + dacllen + sacllen + ownerlen); 563 564 Status = RtlSelfRelativeToAbsoluteSD(fcb->sd, abssd, &abssdlen, dacl, &dacllen, sacl, &sacllen, owner, &ownerlen, 565 group, &grouplen); 566 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) { 567 ERR("RtlSelfRelativeToAbsoluteSD returned %08lx\n", Status); 568 ExFreePool(buf); 569 return; 570 } 571 572 Status = uid_to_sid(fcb->inode_item.st_uid, &usersid); 573 if (!NT_SUCCESS(Status)) { 574 ERR("uid_to_sid returned %08lx\n", Status); 575 ExFreePool(buf); 576 return; 577 } 578 579 RtlSetOwnerSecurityDescriptor(abssd, usersid, false); 580 581 gid_to_sid(fcb->inode_item.st_gid, &groupsid); 582 if (!groupsid) { 583 ERR("out of memory\n"); 584 ExFreePool(usersid); 585 ExFreePool(buf); 586 return; 587 } 588 589 RtlSetGroupSecurityDescriptor(abssd, groupsid, false); 590 591 buflen = 0; 592 593 Status = RtlAbsoluteToSelfRelativeSD(abssd, NULL, &buflen); 594 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) { 595 ERR("RtlAbsoluteToSelfRelativeSD returned %08lx\n", Status); 596 ExFreePool(usersid); 597 ExFreePool(groupsid); 598 ExFreePool(buf); 599 return; 600 } 601 602 if (buflen == 0) { 603 ERR("RtlAbsoluteToSelfRelativeSD returned a buffer size of 0\n"); 604 ExFreePool(usersid); 605 ExFreePool(groupsid); 606 ExFreePool(buf); 607 return; 608 } 609 610 newsd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG); 611 if (!newsd) { 612 ERR("out of memory\n"); 613 ExFreePool(usersid); 614 ExFreePool(groupsid); 615 ExFreePool(buf); 616 return; 617 } 618 619 Status = RtlAbsoluteToSelfRelativeSD(abssd, newsd, &buflen); 620 if (!NT_SUCCESS(Status)) { 621 ERR("RtlAbsoluteToSelfRelativeSD returned %08lx\n", Status); 622 ExFreePool(usersid); 623 ExFreePool(groupsid); 624 ExFreePool(buf); 625 return; 626 } 627 628 ExFreePool(fcb->sd); 629 fcb->sd = newsd; 630 631 ExFreePool(usersid); 632 ExFreePool(groupsid); 633 ExFreePool(buf); 634 } 635 636 static NTSTATUS get_file_security(PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* relsd, ULONG* buflen, SECURITY_INFORMATION flags) { 637 NTSTATUS Status; 638 fcb* fcb = FileObject->FsContext; 639 ccb* ccb = FileObject->FsContext2; 640 file_ref* fileref = ccb ? ccb->fileref : NULL; 641 642 if (fcb->ads) { 643 if (fileref && fileref->parent) 644 fcb = fileref->parent->fcb; 645 else { 646 ERR("could not get parent fcb for stream\n"); 647 return STATUS_INTERNAL_ERROR; 648 } 649 } 650 651 // Why (void**)? Is this a bug in mingw? 652 Status = SeQuerySecurityDescriptorInfo(&flags, relsd, buflen, (void**)&fcb->sd); 653 654 if (Status == STATUS_BUFFER_TOO_SMALL) 655 TRACE("SeQuerySecurityDescriptorInfo returned %08lx\n", Status); 656 else if (!NT_SUCCESS(Status)) 657 ERR("SeQuerySecurityDescriptorInfo returned %08lx\n", Status); 658 659 return Status; 660 } 661 662 _Dispatch_type_(IRP_MJ_QUERY_SECURITY) 663 _Function_class_(DRIVER_DISPATCH) 664 NTSTATUS __stdcall drv_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 665 NTSTATUS Status; 666 SECURITY_DESCRIPTOR* sd; 667 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 668 device_extension* Vcb = DeviceObject->DeviceExtension; 669 ULONG buflen; 670 bool top_level; 671 PFILE_OBJECT FileObject = IrpSp->FileObject; 672 ccb* ccb = FileObject ? FileObject->FsContext2 : NULL; 673 674 FsRtlEnterFileSystem(); 675 676 TRACE("query security\n"); 677 678 top_level = is_top_level(Irp); 679 680 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 681 Status = STATUS_INVALID_DEVICE_REQUEST; 682 goto end; 683 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 684 Status = STATUS_INVALID_PARAMETER; 685 goto end; 686 } 687 688 if (!ccb) { 689 ERR("no ccb\n"); 690 Status = STATUS_INVALID_PARAMETER; 691 goto end; 692 } 693 694 if (Irp->RequestorMode == UserMode && !(ccb->access & READ_CONTROL)) { 695 WARN("insufficient permissions\n"); 696 Status = STATUS_ACCESS_DENIED; 697 goto end; 698 } 699 700 Status = STATUS_SUCCESS; 701 702 Irp->IoStatus.Information = 0; 703 704 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) 705 TRACE("OWNER_SECURITY_INFORMATION\n"); 706 707 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) 708 TRACE("GROUP_SECURITY_INFORMATION\n"); 709 710 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & DACL_SECURITY_INFORMATION) 711 TRACE("DACL_SECURITY_INFORMATION\n"); 712 713 if (IrpSp->Parameters.QuerySecurity.SecurityInformation & SACL_SECURITY_INFORMATION) 714 TRACE("SACL_SECURITY_INFORMATION\n"); 715 716 TRACE("length = %lu\n", IrpSp->Parameters.QuerySecurity.Length); 717 718 sd = map_user_buffer(Irp, NormalPagePriority); 719 TRACE("sd = %p\n", sd); 720 721 if (Irp->MdlAddress && !sd) { 722 ERR("MmGetSystemAddressForMdlSafe returned NULL\n"); 723 Status = STATUS_INSUFFICIENT_RESOURCES; 724 goto end; 725 } 726 727 buflen = IrpSp->Parameters.QuerySecurity.Length; 728 729 Status = get_file_security(IrpSp->FileObject, sd, &buflen, IrpSp->Parameters.QuerySecurity.SecurityInformation); 730 731 if (NT_SUCCESS(Status)) 732 Irp->IoStatus.Information = IrpSp->Parameters.QuerySecurity.Length; 733 else if (Status == STATUS_BUFFER_TOO_SMALL) { 734 Irp->IoStatus.Information = buflen; 735 Status = STATUS_BUFFER_OVERFLOW; 736 } else 737 Irp->IoStatus.Information = 0; 738 739 end: 740 TRACE("Irp->IoStatus.Information = %Iu\n", Irp->IoStatus.Information); 741 742 Irp->IoStatus.Status = Status; 743 744 IoCompleteRequest(Irp, IO_NO_INCREMENT); 745 746 if (top_level) 747 IoSetTopLevelIrp(NULL); 748 749 TRACE("returning %08lx\n", Status); 750 751 FsRtlExitFileSystem(); 752 753 return Status; 754 } 755 756 static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT FileObject, SECURITY_DESCRIPTOR* sd, PSECURITY_INFORMATION flags, PIRP Irp) { 757 NTSTATUS Status; 758 fcb* fcb = FileObject->FsContext; 759 ccb* ccb = FileObject->FsContext2; 760 file_ref* fileref = ccb ? ccb->fileref : NULL; 761 SECURITY_DESCRIPTOR* oldsd; 762 LARGE_INTEGER time; 763 BTRFS_TIME now; 764 765 TRACE("(%p, %p, %p, %lx)\n", Vcb, FileObject, sd, *flags); 766 767 if (Vcb->readonly) 768 return STATUS_MEDIA_WRITE_PROTECTED; 769 770 if (fcb->ads) { 771 if (fileref && fileref->parent) 772 fcb = fileref->parent->fcb; 773 else { 774 ERR("could not find parent fcb for stream\n"); 775 return STATUS_INTERNAL_ERROR; 776 } 777 } 778 779 if (!fcb || !ccb) 780 return STATUS_INVALID_PARAMETER; 781 782 ExAcquireResourceExclusiveLite(fcb->Header.Resource, true); 783 784 if (is_subvol_readonly(fcb->subvol, Irp)) { 785 Status = STATUS_ACCESS_DENIED; 786 goto end; 787 } 788 789 oldsd = fcb->sd; 790 791 Status = SeSetSecurityDescriptorInfo(NULL, flags, sd, (void**)&fcb->sd, PagedPool, IoGetFileObjectGenericMapping()); 792 793 if (!NT_SUCCESS(Status)) { 794 ERR("SeSetSecurityDescriptorInfo returned %08lx\n", Status); 795 goto end; 796 } 797 798 ExFreePool(oldsd); 799 800 KeQuerySystemTime(&time); 801 win_time_to_unix(time, &now); 802 803 fcb->inode_item.transid = Vcb->superblock.generation; 804 805 if (!ccb->user_set_change_time) 806 fcb->inode_item.st_ctime = now; 807 808 fcb->inode_item.sequence++; 809 810 fcb->sd_dirty = true; 811 fcb->sd_deleted = false; 812 fcb->inode_item_changed = true; 813 814 fcb->subvol->root_item.ctransid = Vcb->superblock.generation; 815 fcb->subvol->root_item.ctime = now; 816 817 mark_fcb_dirty(fcb); 818 819 queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, NULL); 820 821 end: 822 ExReleaseResourceLite(fcb->Header.Resource); 823 824 return Status; 825 } 826 827 _Dispatch_type_(IRP_MJ_SET_SECURITY) 828 _Function_class_(DRIVER_DISPATCH) 829 NTSTATUS __stdcall drv_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 830 NTSTATUS Status; 831 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 832 PFILE_OBJECT FileObject = IrpSp->FileObject; 833 ccb* ccb = FileObject ? FileObject->FsContext2 : NULL; 834 device_extension* Vcb = DeviceObject->DeviceExtension; 835 ULONG access_req = 0; 836 bool top_level; 837 838 FsRtlEnterFileSystem(); 839 840 TRACE("set security\n"); 841 842 top_level = is_top_level(Irp); 843 844 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 845 Status = STATUS_INVALID_DEVICE_REQUEST; 846 goto end; 847 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 848 Status = STATUS_INVALID_PARAMETER; 849 goto end; 850 } 851 852 if (!ccb) { 853 ERR("no ccb\n"); 854 Status = STATUS_INVALID_PARAMETER; 855 goto end; 856 } 857 858 Status = STATUS_SUCCESS; 859 860 Irp->IoStatus.Information = 0; 861 862 if (IrpSp->Parameters.SetSecurity.SecurityInformation & OWNER_SECURITY_INFORMATION) { 863 TRACE("OWNER_SECURITY_INFORMATION\n"); 864 access_req |= WRITE_OWNER; 865 } 866 867 if (IrpSp->Parameters.SetSecurity.SecurityInformation & GROUP_SECURITY_INFORMATION) { 868 TRACE("GROUP_SECURITY_INFORMATION\n"); 869 access_req |= WRITE_OWNER; 870 } 871 872 if (IrpSp->Parameters.SetSecurity.SecurityInformation & DACL_SECURITY_INFORMATION) { 873 TRACE("DACL_SECURITY_INFORMATION\n"); 874 access_req |= WRITE_DAC; 875 } 876 877 if (IrpSp->Parameters.SetSecurity.SecurityInformation & SACL_SECURITY_INFORMATION) { 878 TRACE("SACL_SECURITY_INFORMATION\n"); 879 access_req |= ACCESS_SYSTEM_SECURITY; 880 } 881 882 if (Irp->RequestorMode == UserMode && (ccb->access & access_req) != access_req) { 883 Status = STATUS_ACCESS_DENIED; 884 WARN("insufficient privileges\n"); 885 goto end; 886 } 887 888 Status = set_file_security(DeviceObject->DeviceExtension, FileObject, IrpSp->Parameters.SetSecurity.SecurityDescriptor, 889 &IrpSp->Parameters.SetSecurity.SecurityInformation, Irp); 890 891 end: 892 Irp->IoStatus.Status = Status; 893 894 IoCompleteRequest(Irp, IO_NO_INCREMENT); 895 896 TRACE("returning %08lx\n", Status); 897 898 if (top_level) 899 IoSetTopLevelIrp(NULL); 900 901 FsRtlExitFileSystem(); 902 903 return Status; 904 } 905 906 static bool search_for_gid(fcb* fcb, PSID sid) { 907 LIST_ENTRY* le; 908 909 le = gid_map_list.Flink; 910 while (le != &gid_map_list) { 911 gid_map* gm = CONTAINING_RECORD(le, gid_map, listentry); 912 913 if (RtlEqualSid(sid, gm->sid)) { 914 fcb->inode_item.st_gid = gm->gid; 915 return true; 916 } 917 918 le = le->Flink; 919 } 920 921 return false; 922 } 923 924 void find_gid(struct _fcb* fcb, struct _fcb* parfcb, PSECURITY_SUBJECT_CONTEXT subjcont) { 925 NTSTATUS Status; 926 TOKEN_OWNER* to; 927 TOKEN_PRIMARY_GROUP* tpg; 928 TOKEN_GROUPS* tg; 929 930 if (parfcb && parfcb->inode_item.st_mode & S_ISGID) { 931 fcb->inode_item.st_gid = parfcb->inode_item.st_gid; 932 return; 933 } 934 935 ExAcquireResourceSharedLite(&mapping_lock, true); 936 937 if (!subjcont || !subjcont->PrimaryToken || IsListEmpty(&gid_map_list)) { 938 ExReleaseResourceLite(&mapping_lock); 939 return; 940 } 941 942 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenOwner, (void**)&to); 943 if (!NT_SUCCESS(Status)) 944 ERR("SeQueryInformationToken returned %08lx\n", Status); 945 else { 946 if (search_for_gid(fcb, to->Owner)) { 947 ExReleaseResourceLite(&mapping_lock); 948 ExFreePool(to); 949 return; 950 } 951 952 ExFreePool(to); 953 } 954 955 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenPrimaryGroup, (void**)&tpg); 956 if (!NT_SUCCESS(Status)) 957 ERR("SeQueryInformationToken returned %08lx\n", Status); 958 else { 959 if (search_for_gid(fcb, tpg->PrimaryGroup)) { 960 ExReleaseResourceLite(&mapping_lock); 961 ExFreePool(tpg); 962 return; 963 } 964 965 ExFreePool(tpg); 966 } 967 968 Status = SeQueryInformationToken(subjcont->PrimaryToken, TokenGroups, (void**)&tg); 969 if (!NT_SUCCESS(Status)) 970 ERR("SeQueryInformationToken returned %08lx\n", Status); 971 else { 972 ULONG i; 973 974 for (i = 0; i < tg->GroupCount; i++) { 975 if (search_for_gid(fcb, tg->Groups[i].Sid)) { 976 ExReleaseResourceLite(&mapping_lock); 977 ExFreePool(tg); 978 return; 979 } 980 } 981 982 ExFreePool(tg); 983 } 984 985 ExReleaseResourceLite(&mapping_lock); 986 } 987 988 NTSTATUS fcb_get_new_sd(fcb* fcb, file_ref* parfileref, ACCESS_STATE* as) { 989 NTSTATUS Status; 990 PSID owner; 991 BOOLEAN defaulted; 992 993 Status = SeAssignSecurityEx(parfileref ? parfileref->fcb->sd : NULL, as->SecurityDescriptor, (void**)&fcb->sd, NULL, fcb->type == BTRFS_TYPE_DIRECTORY, 994 SEF_SACL_AUTO_INHERIT, &as->SubjectSecurityContext, IoGetFileObjectGenericMapping(), PagedPool); 995 996 if (!NT_SUCCESS(Status)) { 997 ERR("SeAssignSecurityEx returned %08lx\n", Status); 998 return Status; 999 } 1000 1001 Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted); 1002 if (!NT_SUCCESS(Status)) { 1003 ERR("RtlGetOwnerSecurityDescriptor returned %08lx\n", Status); 1004 fcb->inode_item.st_uid = UID_NOBODY; 1005 } else { 1006 fcb->inode_item.st_uid = sid_to_uid(owner); 1007 } 1008 1009 find_gid(fcb, parfileref ? parfileref->fcb : NULL, &as->SubjectSecurityContext); 1010 1011 return STATUS_SUCCESS; 1012 } 1013