1 /* Copyright (c) Mark Harmstone 2016
3 * This file is part of WinBtrfs.
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.
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.
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/>. */
18 #include "btrfs_drv.h"
20 #define SEF_DACL_AUTO_INHERIT 0x01
21 #define SEF_SACL_AUTO_INHERIT 0x02
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
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_ADD_SUBDIRECTORY
, &sid_AU
},
49 // FIXME - Mandatory Label\High Mandatory Level:(OI)(NP)(IO)(NW)
53 extern LIST_ENTRY uid_map_list
;
55 // UINT32 STDCALL get_uid() {
56 // PACCESS_TOKEN at = PsReferencePrimaryToken(PsGetCurrentProcess());
61 // UINT32 uid = UID_NOBODY;
66 // Status = ObOpenObjectByPointer(at, OBJ_KERNEL_HANDLE, NULL, GENERIC_READ, NULL, KernelMode, &h);
67 // if (!NT_SUCCESS(Status)) {
68 // ERR("ObOpenObjectByPointer returned %08x\n", Status);
72 // Status = ZwQueryInformationToken(h, TokenUser, NULL, 0, &len);
73 // if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) {
74 // ERR("ZwQueryInformationToken(1) returned %08x (len = %u)\n", Status, len);
78 // // TRACE("len = %u\n", len);
80 // tu = ExAllocatePoolWithTag(PagedPool, len, ALLOC_TAG);
82 // Status = ZwQueryInformationToken(h, TokenUser, tu, len, &len);
84 // if (!NT_SUCCESS(Status)) {
85 // ERR("ZwQueryInformationToken(2) returned %08x\n", Status);
89 // size = 8 + (4 * ((sid_header*)tu->User.Sid)->elements);
91 // le = uid_map_list.Flink;
92 // while (le != &uid_map_list) {
93 // um = CONTAINING_RECORD(le, uid_map, listentry);
95 // if (((sid_header*)um->sid)->elements == ((sid_header*)tu->User.Sid)->elements &&
96 // RtlCompareMemory(um->sid, tu->User.Sid, size) == size) {
104 // // sid_to_string(tu->User.Sid, s);
106 // // TRACE("got SID: %s\n", s);
107 // TRACE("uid = %u\n", uid);
116 // PsDereferencePrimaryToken(at);
121 void add_user_mapping(WCHAR
* sidstring
, ULONG sidstringlength
, UINT32 uid
) {
130 if (sidstringlength
< 4 ||
131 sidstring
[0] != 'S' ||
132 sidstring
[1] != '-' ||
133 sidstring
[2] != '1' ||
134 sidstring
[3] != '-') {
135 ERR("invalid SID\n");
139 sidstring
= &sidstring
[4];
140 sidstringlength
-= 4;
143 for (i
= 0; i
< sidstringlength
; i
++) {
144 if (sidstring
[i
] == '-') {
150 sidsize
= 8 + (numdashes
* 4);
151 sid
= ExAllocatePoolWithTag(PagedPool
, sidsize
, ALLOC_TAG
);
153 ERR("out of memory\n");
157 sid
->revision
= 0x01;
158 sid
->elements
= numdashes
;
161 while (sidstringlength
> 0) {
164 while (sidstring
[i
] != '-' && i
< sidstringlength
) {
165 if (sidstring
[i
] >= '0' && sidstring
[i
] <= '9') {
167 val
+= sidstring
[i
] - '0';
175 TRACE("val = %u, i = %u, ssl = %u\n", (UINT32
)val
, i
, sidstringlength
);
178 sid
->auth
[0] = (val
& 0xff0000000000) >> 40;
179 sid
->auth
[1] = (val
& 0xff00000000) >> 32;
180 sid
->auth
[2] = (val
& 0xff000000) >> 24;
181 sid
->auth
[3] = (val
& 0xff0000) >> 16;
182 sid
->auth
[4] = (val
& 0xff00) >> 8;
183 sid
->auth
[5] = val
& 0xff;
185 sid
->nums
[np
-1] = (UINT32
)val
;
190 if (sidstringlength
> i
) {
191 sidstringlength
-= i
;
193 sidstring
= &sidstring
[i
];
198 // sid_to_string(sid, s);
201 um
= ExAllocatePoolWithTag(PagedPool
, sizeof(uid_map
), ALLOC_TAG
);
203 ERR("out of memory\n");
210 InsertTailList(&uid_map_list
, &um
->listentry
);
213 static void uid_to_sid(UINT32 uid
, PSID
* sid
) {
219 le
= uid_map_list
.Flink
;
220 while (le
!= &uid_map_list
) {
221 um
= CONTAINING_RECORD(le
, uid_map
, listentry
);
223 if (um
->uid
== uid
) {
224 *sid
= ExAllocatePoolWithTag(PagedPool
, RtlLengthSid(um
->sid
), ALLOC_TAG
);
226 ERR("out of memory\n");
230 RtlCopyMemory(*sid
, um
->sid
, RtlLengthSid(um
->sid
));
237 if (uid
== 0) { // root
238 // FIXME - find actual Administrator account, rather than SYSTEM (S-1-5-18)
239 // (of form S-1-5-21-...-500)
243 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
) + ((els
- 1) * sizeof(UINT32
)), ALLOC_TAG
);
245 ERR("out of memory\n");
262 // fallback to S-1-22-1-X, Samba's SID scheme
263 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
), ALLOC_TAG
);
265 ERR("out of memory\n");
287 UINT32
sid_to_uid(PSID sid
) {
290 sid_header
* sh
= sid
;
292 le
= uid_map_list
.Flink
;
293 while (le
!= &uid_map_list
) {
294 um
= CONTAINING_RECORD(le
, uid_map
, listentry
);
296 if (RtlEqualSid(sid
, um
->sid
))
302 if (RtlEqualSid(sid
, &sid_SY
))
305 // Samba's SID scheme: S-1-22-1-X
306 if (sh
->revision
== 1 && sh
->elements
== 2 && sh
->auth
[0] == 0 && sh
->auth
[1] == 0 && sh
->auth
[2] == 0 && sh
->auth
[3] == 0 &&
307 sh
->auth
[4] == 0 && sh
->auth
[5] == 22 && sh
->nums
[0] == 1)
313 static void gid_to_sid(UINT32 gid
, PSID
* sid
) {
317 // FIXME - do this properly?
319 // fallback to S-1-22-2-X, Samba's SID scheme
321 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
) + ((els
- 1) * sizeof(UINT32
)), ALLOC_TAG
);
323 ERR("out of memory\n");
344 static ACL
* load_default_acl() {
347 ACCESS_ALLOWED_ACE
* aaa
;
352 while (def_dacls
[i
].sid
) {
353 size
+= sizeof(ACCESS_ALLOWED_ACE
);
354 size
+= 8 + (def_dacls
[i
].sid
->elements
* sizeof(UINT32
)) - sizeof(ULONG
);
358 acl
= ExAllocatePoolWithTag(PagedPool
, size
, ALLOC_TAG
);
360 ERR("out of memory\n");
364 acl
->AclRevision
= ACL_REVISION
;
370 aaa
= (ACCESS_ALLOWED_ACE
*)&acl
[1];
372 while (def_dacls
[i
].sid
) {
373 aaa
->Header
.AceType
= ACCESS_ALLOWED_ACE_TYPE
;
374 aaa
->Header
.AceFlags
= def_dacls
[i
].flags
;
375 aaa
->Header
.AceSize
= sizeof(ACCESS_ALLOWED_ACE
) - sizeof(ULONG
) + 8 + (def_dacls
[i
].sid
->elements
* sizeof(UINT32
));
376 aaa
->Mask
= def_dacls
[i
].mask
;
378 RtlCopyMemory(&aaa
->SidStart
, def_dacls
[i
].sid
, 8 + (def_dacls
[i
].sid
->elements
* sizeof(UINT32
)));
380 aaa
= (ACCESS_ALLOWED_ACE
*)((UINT8
*)aaa
+ aaa
->Header
.AceSize
);
388 // static void STDCALL sid_to_string(PSID sid, char* s) {
389 // sid_header* sh = (sid_header*)sid;
390 // LARGE_INTEGER authnum;
393 // authnum.LowPart = sh->auth[5] | (sh->auth[4] << 8) | (sh->auth[3] << 16) | (sh->auth[2] << 24);
394 // authnum.HighPart = sh->auth[1] | (sh->auth[0] << 8);
396 // sprintf(s, "S-%u-%u", sh->revision, (UINT32)authnum.QuadPart);
398 // for (i = 0; i < sh->elements; i++) {
399 // sprintf(s, "%s-%u", s, sh->nums[i]);
403 static BOOL
get_sd_from_xattr(fcb
* fcb
) {
408 if (!get_xattr(fcb
->Vcb
, fcb
->subvol
, fcb
->inode
, EA_NTACL
, EA_NTACL_HASH
, (UINT8
**)&fcb
->sd
, (UINT16
*)&buflen
))
411 TRACE("using xattr " EA_NTACL
" for security descriptor\n");
413 if (fcb
->inode_item
.st_uid
!= UID_NOBODY
) {
416 Status
= RtlGetOwnerSecurityDescriptor(fcb
->sd
, &sid
, &defaulted
);
417 if (!NT_SUCCESS(Status
)) {
418 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status
);
420 uid_to_sid(fcb
->inode_item
.st_uid
, &usersid
);
423 ERR("out of memory\n");
427 if (!RtlEqualSid(sid
, usersid
)) {
428 SECURITY_DESCRIPTOR
*newsd
, *newsd2
;
429 ULONG sdsize
, daclsize
, saclsize
, ownersize
, groupsize
;
433 sdsize
= daclsize
= saclsize
= ownersize
= groupsize
= 0;
435 Status
= RtlSelfRelativeToAbsoluteSD(fcb
->sd
, NULL
, &sdsize
, NULL
, &daclsize
, NULL
, &saclsize
, NULL
, &ownersize
, NULL
, &groupsize
);
437 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
) {
438 ERR("RtlSelfRelativeToAbsoluteSD 1 returned %08x\n", Status
);
441 TRACE("sdsize = %u, daclsize = %u, saclsize = %u, ownersize = %u, groupsize = %u\n", sdsize
, daclsize
, saclsize
, ownersize
, groupsize
);
443 newsd2
= sdsize
== 0 ? NULL
: ExAllocatePoolWithTag(PagedPool
, sdsize
, ALLOC_TAG
);
444 dacl
= daclsize
== 0 ? NULL
: ExAllocatePoolWithTag(PagedPool
, daclsize
, ALLOC_TAG
);
445 sacl
= saclsize
== 0 ? NULL
: ExAllocatePoolWithTag(PagedPool
, saclsize
, ALLOC_TAG
);
446 owner
= ownersize
== 0 ? NULL
: ExAllocatePoolWithTag(PagedPool
, ownersize
, ALLOC_TAG
);
447 group
= groupsize
== 0 ? NULL
: ExAllocatePoolWithTag(PagedPool
, groupsize
, ALLOC_TAG
);
449 if ((sdsize
> 0 && !newsd2
) || (daclsize
> 0 && !dacl
) || (saclsize
> 0 && !sacl
) || (ownersize
> 0 && !owner
) || (groupsize
> 0 && !group
)) {
450 ERR("out of memory\n");
451 if (newsd2
) ExFreePool(newsd2
);
452 if (dacl
) ExFreePool(dacl
);
453 if (sacl
) ExFreePool(sacl
);
454 if (owner
) ExFreePool(owner
);
455 if (group
) ExFreePool(group
);
460 Status
= RtlSelfRelativeToAbsoluteSD(fcb
->sd
, newsd2
, &sdsize
, dacl
, &daclsize
, sacl
, &saclsize
, owner
, &ownersize
, group
, &groupsize
);
462 if (!NT_SUCCESS(Status
)) {
463 ERR("RtlSelfRelativeToAbsoluteSD returned %08x\n", Status
);
464 if (newsd2
) ExFreePool(newsd2
);
465 if (dacl
) ExFreePool(dacl
);
466 if (sacl
) ExFreePool(sacl
);
467 if (owner
) ExFreePool(owner
);
468 if (group
) ExFreePool(group
);
473 Status
= RtlSetOwnerSecurityDescriptor(newsd2
, usersid
, FALSE
);
474 if (!NT_SUCCESS(Status
)) {
475 ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status
);
476 if (newsd2
) ExFreePool(newsd2
);
477 if (dacl
) ExFreePool(dacl
);
478 if (sacl
) ExFreePool(sacl
);
479 if (owner
) ExFreePool(owner
);
480 if (group
) ExFreePool(group
);
486 Status
= RtlAbsoluteToSelfRelativeSD(newsd2
, NULL
, &buflen
);
487 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_TOO_SMALL
) {
488 ERR("RtlAbsoluteToSelfRelativeSD 1 returned %08x\n", Status
);
489 if (newsd2
) ExFreePool(newsd2
);
490 if (dacl
) ExFreePool(dacl
);
491 if (sacl
) ExFreePool(sacl
);
492 if (owner
) ExFreePool(owner
);
493 if (group
) ExFreePool(group
);
498 if (buflen
== 0 || NT_SUCCESS(Status
)) {
499 ERR("RtlAbsoluteToSelfRelativeSD said SD is zero-length\n");
500 if (newsd2
) ExFreePool(newsd2
);
501 if (dacl
) ExFreePool(dacl
);
502 if (sacl
) ExFreePool(sacl
);
503 if (owner
) ExFreePool(owner
);
504 if (group
) ExFreePool(group
);
509 newsd
= ExAllocatePoolWithTag(PagedPool
, buflen
, ALLOC_TAG
);
511 ERR("out of memory\n");
512 if (newsd2
) ExFreePool(newsd2
);
513 if (dacl
) ExFreePool(dacl
);
514 if (sacl
) ExFreePool(sacl
);
515 if (owner
) ExFreePool(owner
);
516 if (group
) ExFreePool(group
);
521 Status
= RtlAbsoluteToSelfRelativeSD(newsd2
, newsd
, &buflen
);
523 if (!NT_SUCCESS(Status
)) {
524 ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status
);
525 if (newsd2
) ExFreePool(newsd2
);
526 if (dacl
) ExFreePool(dacl
);
527 if (sacl
) ExFreePool(sacl
);
528 if (owner
) ExFreePool(owner
);
529 if (group
) ExFreePool(group
);
539 if (newsd2
) ExFreePool(newsd2
);
540 if (dacl
) ExFreePool(dacl
);
541 if (sacl
) ExFreePool(sacl
);
542 if (owner
) ExFreePool(owner
);
543 if (group
) ExFreePool(group
);
550 // FIXME - check GID here if not GID_NOBODY
555 static void get_top_level_sd(fcb
* fcb
) {
557 SECURITY_DESCRIPTOR sd
;
560 PSID usersid
= NULL
, groupsid
= NULL
;
562 Status
= RtlCreateSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
);
564 if (!NT_SUCCESS(Status
)) {
565 ERR("RtlCreateSecurityDescriptor returned %08x\n", Status
);
569 // if (fcb->inode_item.st_uid != UID_NOBODY) {
570 uid_to_sid(fcb
->inode_item
.st_uid
, &usersid
);
572 ERR("out of memory\n");
576 RtlSetOwnerSecurityDescriptor(&sd
, usersid
, FALSE
);
578 if (!NT_SUCCESS(Status
)) {
579 ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status
);
584 // if (fcb->inode_item.st_gid != GID_NOBODY) {
585 gid_to_sid(fcb
->inode_item
.st_gid
, &groupsid
);
587 ERR("out of memory\n");
588 Status
= STATUS_INSUFFICIENT_RESOURCES
;
592 RtlSetGroupSecurityDescriptor(&sd
, groupsid
, FALSE
);
594 if (!NT_SUCCESS(Status
)) {
595 ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status
);
600 acl
= load_default_acl();
603 ERR("out of memory\n");
607 Status
= RtlSetDaclSecurityDescriptor(&sd
, TRUE
, acl
, FALSE
);
609 if (!NT_SUCCESS(Status
)) {
610 ERR("RtlSetDaclSecurityDescriptor returned %08x\n", Status
);
614 // FIXME - SACL_SECURITY_INFORMATION
619 Status
= RtlAbsoluteToSelfRelativeSD(&sd
, NULL
, &buflen
);
620 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_BUFFER_TOO_SMALL
) {
621 ERR("RtlAbsoluteToSelfRelativeSD 1 returned %08x\n", Status
);
625 // fcb->sdlen = buflen;
627 if (buflen
== 0 || Status
== STATUS_SUCCESS
) {
628 TRACE("RtlAbsoluteToSelfRelativeSD said SD is zero-length\n");
632 fcb
->sd
= ExAllocatePoolWithTag(PagedPool
, buflen
, ALLOC_TAG
);
634 ERR("out of memory\n");
635 Status
= STATUS_INSUFFICIENT_RESOURCES
;
639 Status
= RtlAbsoluteToSelfRelativeSD(&sd
, fcb
->sd
, &buflen
);
641 if (!NT_SUCCESS(Status
)) {
642 ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status
);
654 ExFreePool(groupsid
);
657 void fcb_get_sd(fcb
* fcb
, struct _fcb
* parent
) {
659 PSID usersid
= NULL
, groupsid
= NULL
;
660 SECURITY_SUBJECT_CONTEXT subjcont
;
662 if (get_sd_from_xattr(fcb
))
666 get_top_level_sd(fcb
);
670 SeCaptureSubjectContext(&subjcont
);
672 Status
= SeAssignSecurityEx(parent
->sd
, NULL
, (void**)&fcb
->sd
, NULL
, fcb
->type
== BTRFS_TYPE_DIRECTORY
, SEF_DACL_AUTO_INHERIT
,
673 &subjcont
, IoGetFileObjectGenericMapping(), PagedPool
);
674 if (!NT_SUCCESS(Status
)) {
675 ERR("SeAssignSecurityEx returned %08x\n", Status
);
678 uid_to_sid(fcb
->inode_item
.st_uid
, &usersid
);
680 ERR("out of memory\n");
684 RtlSetOwnerSecurityDescriptor(&fcb
->sd
, usersid
, FALSE
);
686 gid_to_sid(fcb
->inode_item
.st_gid
, &groupsid
);
688 ERR("out of memory\n");
692 RtlSetGroupSecurityDescriptor(&fcb
->sd
, groupsid
, FALSE
);
695 ExFreePool(groupsid
);
698 static NTSTATUS STDCALL
get_file_security(device_extension
* Vcb
, PFILE_OBJECT FileObject
, SECURITY_DESCRIPTOR
* relsd
, ULONG
* buflen
, SECURITY_INFORMATION flags
) {
700 fcb
* fcb
= FileObject
->FsContext
;
701 ccb
* ccb
= FileObject
->FsContext2
;
702 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
705 if (fileref
&& fileref
->parent
)
706 fcb
= fileref
->parent
->fcb
;
708 ERR("could not get parent fcb for stream\n");
709 return STATUS_INTERNAL_ERROR
;
713 // TRACE("buflen = %u, fcb->sdlen = %u\n", *buflen, fcb->sdlen);
715 // Why (void**)? Is this a bug in mingw?
716 Status
= SeQuerySecurityDescriptorInfo(&flags
, relsd
, buflen
, (void**)&fcb
->sd
);
718 if (Status
== STATUS_BUFFER_TOO_SMALL
)
719 TRACE("SeQuerySecurityDescriptorInfo returned %08x\n", Status
);
720 else if (!NT_SUCCESS(Status
))
721 ERR("SeQuerySecurityDescriptorInfo returned %08x\n", Status
);
726 NTSTATUS STDCALL
drv_query_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
728 SECURITY_DESCRIPTOR
* sd
;
729 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
730 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
733 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
734 ccb
* ccb
= FileObject
? FileObject
->FsContext2
: NULL
;
736 TRACE("query security\n");
738 FsRtlEnterFileSystem();
740 top_level
= is_top_level(Irp
);
742 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
743 Status
= part0_passthrough(DeviceObject
, Irp
);
749 Status
= STATUS_INVALID_PARAMETER
;
753 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& READ_CONTROL
)) {
754 WARN("insufficient permissions\n");
755 Status
= STATUS_ACCESS_DENIED
;
759 Status
= STATUS_SUCCESS
;
761 Irp
->IoStatus
.Information
= 0;
763 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& OWNER_SECURITY_INFORMATION
)
764 TRACE("OWNER_SECURITY_INFORMATION\n");
766 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& GROUP_SECURITY_INFORMATION
)
767 TRACE("GROUP_SECURITY_INFORMATION\n");
769 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& DACL_SECURITY_INFORMATION
)
770 TRACE("DACL_SECURITY_INFORMATION\n");
772 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& SACL_SECURITY_INFORMATION
)
773 TRACE("SACL_SECURITY_INFORMATION\n");
775 TRACE("length = %u\n", IrpSp
->Parameters
.QuerySecurity
.Length
);
777 sd
= map_user_buffer(Irp
);
778 // sd = Irp->AssociatedIrp.SystemBuffer;
779 TRACE("sd = %p\n", sd
);
781 if (Irp
->MdlAddress
&& !sd
) {
782 ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
783 Status
= STATUS_INSUFFICIENT_RESOURCES
;
787 buflen
= IrpSp
->Parameters
.QuerySecurity
.Length
;
789 Status
= get_file_security(Vcb
, IrpSp
->FileObject
, sd
, &buflen
, IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
);
791 if (NT_SUCCESS(Status
))
792 Irp
->IoStatus
.Information
= IrpSp
->Parameters
.QuerySecurity
.Length
;
793 else if (Status
== STATUS_BUFFER_TOO_SMALL
) {
794 Irp
->IoStatus
.Information
= buflen
;
795 Status
= STATUS_BUFFER_OVERFLOW
;
797 Irp
->IoStatus
.Information
= 0;
800 TRACE("Irp->IoStatus.Information = %u\n", Irp
->IoStatus
.Information
);
802 Irp
->IoStatus
.Status
= Status
;
804 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
808 IoSetTopLevelIrp(NULL
);
810 FsRtlExitFileSystem();
812 TRACE("returning %08x\n", Status
);
817 static NTSTATUS STDCALL
set_file_security(device_extension
* Vcb
, PFILE_OBJECT FileObject
, SECURITY_DESCRIPTOR
* sd
, SECURITY_INFORMATION flags
) {
819 fcb
* fcb
= FileObject
->FsContext
;
820 ccb
* ccb
= FileObject
->FsContext2
;
821 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
822 SECURITY_DESCRIPTOR
* oldsd
;
826 TRACE("(%p, %p, %p, %x)\n", Vcb
, FileObject
, sd
, flags
);
829 return STATUS_MEDIA_WRITE_PROTECTED
;
832 if (fileref
&& fileref
->parent
)
833 fcb
= fileref
->parent
->fcb
;
835 ERR("could not find parent fcb for stream\n");
836 Status
= STATUS_INTERNAL_ERROR
;
841 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
843 if (fcb
->subvol
->root_item
.flags
& BTRFS_SUBVOL_READONLY
) {
844 Status
= STATUS_ACCESS_DENIED
;
850 Status
= SeSetSecurityDescriptorInfo(NULL
, &flags
, sd
, (void**)&fcb
->sd
, PagedPool
, IoGetFileObjectGenericMapping());
852 if (!NT_SUCCESS(Status
)) {
853 ERR("SeSetSecurityDescriptorInfo returned %08x\n", Status
);
859 KeQuerySystemTime(&time
);
860 win_time_to_unix(time
, &now
);
862 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
863 fcb
->inode_item
.st_ctime
= now
;
864 fcb
->inode_item
.sequence
++;
866 if (flags
& OWNER_SECURITY_INFORMATION
) {
870 Status
= RtlGetOwnerSecurityDescriptor(sd
, &owner
, &defaulted
);
872 if (!NT_SUCCESS(Status
)) {
873 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status
);
877 fcb
->inode_item
.st_uid
= sid_to_uid(owner
);
880 fcb
->sd_dirty
= TRUE
;
882 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
883 fcb
->subvol
->root_item
.ctime
= now
;
887 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_SECURITY
, FILE_ACTION_MODIFIED
);
890 ExReleaseResourceLite(fcb
->Header
.Resource
);
895 NTSTATUS STDCALL
drv_set_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
897 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
898 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
899 ccb
* ccb
= FileObject
? FileObject
->FsContext2
: NULL
;
900 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
901 ULONG access_req
= 0;
904 TRACE("set security\n");
906 FsRtlEnterFileSystem();
908 top_level
= is_top_level(Irp
);
910 if (Vcb
&& Vcb
->type
== VCB_TYPE_PARTITION0
) {
911 Status
= part0_passthrough(DeviceObject
, Irp
);
917 Status
= STATUS_INVALID_PARAMETER
;
921 Status
= STATUS_SUCCESS
;
923 Irp
->IoStatus
.Information
= 0;
925 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& OWNER_SECURITY_INFORMATION
) {
926 TRACE("OWNER_SECURITY_INFORMATION\n");
927 access_req
|= WRITE_OWNER
;
930 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& GROUP_SECURITY_INFORMATION
) {
931 TRACE("GROUP_SECURITY_INFORMATION\n");
932 access_req
|= WRITE_OWNER
;
935 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& DACL_SECURITY_INFORMATION
) {
936 TRACE("DACL_SECURITY_INFORMATION\n");
937 access_req
|= WRITE_DAC
;
940 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& SACL_SECURITY_INFORMATION
) {
941 TRACE("SACL_SECURITY_INFORMATION\n");
942 access_req
|= ACCESS_SYSTEM_SECURITY
;
945 if ((ccb
->access
& access_req
) != access_req
) {
946 Status
= STATUS_ACCESS_DENIED
;
947 WARN("insufficient privileges\n");
951 Status
= set_file_security(DeviceObject
->DeviceExtension
, FileObject
, IrpSp
->Parameters
.SetSecurity
.SecurityDescriptor
,
952 IrpSp
->Parameters
.SetSecurity
.SecurityInformation
);
955 Irp
->IoStatus
.Status
= Status
;
957 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
959 TRACE("returning %08x\n", Status
);
963 IoSetTopLevelIrp(NULL
);
965 FsRtlExitFileSystem();
970 NTSTATUS
fcb_get_new_sd(fcb
* fcb
, file_ref
* parfileref
, ACCESS_STATE
* as
) {
975 Status
= SeAssignSecurityEx(parfileref
? parfileref
->fcb
->sd
: NULL
, as
->SecurityDescriptor
, (void**)&fcb
->sd
, NULL
, fcb
->type
== BTRFS_TYPE_DIRECTORY
,
976 SEF_SACL_AUTO_INHERIT
, &as
->SubjectSecurityContext
, IoGetFileObjectGenericMapping(), PagedPool
);
978 if (!NT_SUCCESS(Status
)) {
979 ERR("SeAssignSecurityEx returned %08x\n", Status
);
983 Status
= RtlGetOwnerSecurityDescriptor(fcb
->sd
, &owner
, &defaulted
);
984 if (!NT_SUCCESS(Status
)) {
985 ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status
);
986 fcb
->inode_item
.st_uid
= UID_NOBODY
;
988 fcb
->inode_item
.st_uid
= sid_to_uid(&owner
);
991 return STATUS_SUCCESS
;