1 /* Copyright (c) Mark Harmstone 2016-17
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_GENERIC_READ
| FILE_GENERIC_WRITE
| FILE_GENERIC_EXECUTE
| DELETE
, &sid_AU
},
49 // FIXME - Mandatory Label\High Mandatory Level:(OI)(NP)(IO)(NW)
53 extern LIST_ENTRY uid_map_list
, gid_map_list
;
54 extern ERESOURCE mapping_lock
;
56 void add_user_mapping(WCHAR
* sidstring
, ULONG sidstringlength
, UINT32 uid
) {
64 if (sidstringlength
< 4 ||
65 sidstring
[0] != 'S' ||
66 sidstring
[1] != '-' ||
67 sidstring
[2] != '1' ||
68 sidstring
[3] != '-') {
73 sidstring
= &sidstring
[4];
77 for (i
= 0; i
< sidstringlength
; i
++) {
78 if (sidstring
[i
] == '-') {
84 sidsize
= 8 + (numdashes
* 4);
85 sid
= ExAllocatePoolWithTag(PagedPool
, sidsize
, ALLOC_TAG
);
87 ERR("out of memory\n");
92 sid
->elements
= numdashes
;
95 while (sidstringlength
> 0) {
98 while (sidstring
[i
] != '-' && i
< sidstringlength
) {
99 if (sidstring
[i
] >= '0' && sidstring
[i
] <= '9') {
101 val
+= sidstring
[i
] - '0';
109 TRACE("val = %u, i = %u, ssl = %u\n", (UINT32
)val
, i
, sidstringlength
);
112 sid
->auth
[0] = (UINT8
)((val
& 0xff0000000000) >> 40);
113 sid
->auth
[1] = (UINT8
)((val
& 0xff00000000) >> 32);
114 sid
->auth
[2] = (UINT8
)((val
& 0xff000000) >> 24);
115 sid
->auth
[3] = (UINT8
)((val
& 0xff0000) >> 16);
116 sid
->auth
[4] = (UINT8
)((val
& 0xff00) >> 8);
117 sid
->auth
[5] = val
& 0xff;
119 sid
->nums
[np
-1] = (UINT32
)val
;
124 if (sidstringlength
> i
) {
125 sidstringlength
-= i
;
127 sidstring
= &sidstring
[i
];
132 um
= ExAllocatePoolWithTag(PagedPool
, sizeof(uid_map
), ALLOC_TAG
);
134 ERR("out of memory\n");
142 InsertTailList(&uid_map_list
, &um
->listentry
);
145 void add_group_mapping(WCHAR
* sidstring
, ULONG sidstringlength
, UINT32 gid
) {
153 if (sidstringlength
< 4 || sidstring
[0] != 'S' || sidstring
[1] != '-' || sidstring
[2] != '1' || sidstring
[3] != '-') {
154 ERR("invalid SID\n");
158 sidstring
= &sidstring
[4];
159 sidstringlength
-= 4;
162 for (i
= 0; i
< sidstringlength
; i
++) {
163 if (sidstring
[i
] == '-') {
169 sidsize
= 8 + (numdashes
* 4);
170 sid
= ExAllocatePoolWithTag(PagedPool
, sidsize
, ALLOC_TAG
);
172 ERR("out of memory\n");
176 sid
->revision
= 0x01;
177 sid
->elements
= numdashes
;
180 while (sidstringlength
> 0) {
183 while (sidstring
[i
] != '-' && i
< sidstringlength
) {
184 if (sidstring
[i
] >= '0' && sidstring
[i
] <= '9') {
186 val
+= sidstring
[i
] - '0';
194 TRACE("val = %u, i = %u, ssl = %u\n", (UINT32
)val
, i
, sidstringlength
);
197 sid
->auth
[0] = (UINT8
)((val
& 0xff0000000000) >> 40);
198 sid
->auth
[1] = (UINT8
)((val
& 0xff00000000) >> 32);
199 sid
->auth
[2] = (UINT8
)((val
& 0xff000000) >> 24);
200 sid
->auth
[3] = (UINT8
)((val
& 0xff0000) >> 16);
201 sid
->auth
[4] = (UINT8
)((val
& 0xff00) >> 8);
202 sid
->auth
[5] = val
& 0xff;
204 sid
->nums
[np
-1] = (UINT32
)val
;
208 if (sidstringlength
> i
) {
209 sidstringlength
-= i
;
211 sidstring
= &sidstring
[i
];
216 gm
= ExAllocatePoolWithTag(PagedPool
, sizeof(gid_map
), ALLOC_TAG
);
218 ERR("out of memory\n");
226 InsertTailList(&gid_map_list
, &gm
->listentry
);
229 NTSTATUS
uid_to_sid(UINT32 uid
, PSID
* sid
) {
234 ExAcquireResourceSharedLite(&mapping_lock
, TRUE
);
236 le
= uid_map_list
.Flink
;
237 while (le
!= &uid_map_list
) {
238 uid_map
* um
= CONTAINING_RECORD(le
, uid_map
, listentry
);
240 if (um
->uid
== uid
) {
241 *sid
= ExAllocatePoolWithTag(PagedPool
, RtlLengthSid(um
->sid
), ALLOC_TAG
);
243 ERR("out of memory\n");
244 ExReleaseResourceLite(&mapping_lock
);
245 return STATUS_INSUFFICIENT_RESOURCES
;
248 RtlCopyMemory(*sid
, um
->sid
, RtlLengthSid(um
->sid
));
249 ExReleaseResourceLite(&mapping_lock
);
250 return STATUS_SUCCESS
;
256 ExReleaseResourceLite(&mapping_lock
);
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)
264 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
) + ((els
- 1) * sizeof(UINT32
)), ALLOC_TAG
);
266 ERR("out of memory\n");
268 return STATUS_INSUFFICIENT_RESOURCES
;
283 // fallback to S-1-22-1-X, Samba's SID scheme
284 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
), ALLOC_TAG
);
286 ERR("out of memory\n");
288 return STATUS_INSUFFICIENT_RESOURCES
;
307 return STATUS_SUCCESS
;
310 UINT32
sid_to_uid(PSID sid
) {
312 sid_header
* sh
= sid
;
314 ExAcquireResourceSharedLite(&mapping_lock
, TRUE
);
316 le
= uid_map_list
.Flink
;
317 while (le
!= &uid_map_list
) {
318 uid_map
* um
= CONTAINING_RECORD(le
, uid_map
, listentry
);
320 if (RtlEqualSid(sid
, um
->sid
)) {
321 ExReleaseResourceLite(&mapping_lock
);
328 ExReleaseResourceLite(&mapping_lock
);
330 if (RtlEqualSid(sid
, &sid_SY
))
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)
341 static void gid_to_sid(UINT32 gid
, PSID
* sid
) {
345 // FIXME - do this properly?
347 // fallback to S-1-22-2-X, Samba's SID scheme
349 sh
= ExAllocatePoolWithTag(PagedPool
, sizeof(sid_header
) + ((els
- 1) * sizeof(UINT32
)), ALLOC_TAG
);
351 ERR("out of memory\n");
372 static ACL
* load_default_acl() {
375 ACCESS_ALLOWED_ACE
* aaa
;
379 while (def_dacls
[i
].sid
) {
380 size
+= sizeof(ACCESS_ALLOWED_ACE
);
381 size
+= 8 + (def_dacls
[i
].sid
->elements
* sizeof(UINT32
)) - sizeof(ULONG
);
385 acl
= ExAllocatePoolWithTag(PagedPool
, size
, ALLOC_TAG
);
387 ERR("out of memory\n");
391 acl
->AclRevision
= ACL_REVISION
;
397 aaa
= (ACCESS_ALLOWED_ACE
*)&acl
[1];
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
));
403 aaa
->Mask
= def_dacls
[i
].mask
;
405 RtlCopyMemory(&aaa
->SidStart
, def_dacls
[i
].sid
, 8 + (def_dacls
[i
].sid
->elements
* sizeof(UINT32
)));
407 aaa
= (ACCESS_ALLOWED_ACE
*)((UINT8
*)aaa
+ aaa
->Header
.AceSize
);
415 static void get_top_level_sd(fcb
* fcb
) {
417 SECURITY_DESCRIPTOR sd
;
420 PSID usersid
= NULL
, groupsid
= NULL
;
422 Status
= RtlCreateSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
);
424 if (!NT_SUCCESS(Status
)) {
425 ERR("RtlCreateSecurityDescriptor returned %08x\n", Status
);
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
);
435 RtlSetOwnerSecurityDescriptor(&sd
, usersid
, FALSE
);
437 if (!NT_SUCCESS(Status
)) {
438 ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status
);
442 gid_to_sid(fcb
->inode_item
.st_gid
, &groupsid
);
444 ERR("out of memory\n");
445 Status
= STATUS_INSUFFICIENT_RESOURCES
;
449 RtlSetGroupSecurityDescriptor(&sd
, groupsid
, FALSE
);
451 if (!NT_SUCCESS(Status
)) {
452 ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status
);
456 acl
= load_default_acl();
459 ERR("out of memory\n");
463 Status
= RtlSetDaclSecurityDescriptor(&sd
, TRUE
, acl
, FALSE
);
465 if (!NT_SUCCESS(Status
)) {
466 ERR("RtlSetDaclSecurityDescriptor returned %08x\n", Status
);
470 // FIXME - SACL_SECURITY_INFORMATION
475 Status
= RtlAbsoluteToSelfRelativeSD(&sd
, NULL
, &buflen
);
476 if (Status
!= STATUS_SUCCESS
&& Status
!= STATUS_BUFFER_TOO_SMALL
) {
477 ERR("RtlAbsoluteToSelfRelativeSD 1 returned %08x\n", Status
);
481 if (buflen
== 0 || Status
== STATUS_SUCCESS
) {
482 TRACE("RtlAbsoluteToSelfRelativeSD said SD is zero-length\n");
486 fcb
->sd
= ExAllocatePoolWithTag(PagedPool
, buflen
, ALLOC_TAG
);
488 ERR("out of memory\n");
489 Status
= STATUS_INSUFFICIENT_RESOURCES
;
493 Status
= RtlAbsoluteToSelfRelativeSD(&sd
, fcb
->sd
, &buflen
);
495 if (!NT_SUCCESS(Status
)) {
496 ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status
);
508 ExFreePool(groupsid
);
511 void fcb_get_sd(fcb
* fcb
, struct _fcb
* parent
, BOOL look_for_xattr
, PIRP Irp
) {
513 PSID usersid
= NULL
, groupsid
= NULL
;
514 SECURITY_SUBJECT_CONTEXT subjcont
;
517 if (look_for_xattr
&& get_xattr(fcb
->Vcb
, fcb
->subvol
, fcb
->inode
, EA_NTACL
, EA_NTACL_HASH
, (UINT8
**)&fcb
->sd
, (UINT16
*)&buflen
, Irp
))
521 get_top_level_sd(fcb
);
525 SeCaptureSubjectContext(&subjcont
);
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
);
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
);
539 RtlSetOwnerSecurityDescriptor(&fcb
->sd
, usersid
, FALSE
);
541 gid_to_sid(fcb
->inode_item
.st_gid
, &groupsid
);
543 ERR("out of memory\n");
547 RtlSetGroupSecurityDescriptor(&fcb
->sd
, groupsid
, FALSE
);
550 ExFreePool(groupsid
);
553 static NTSTATUS
get_file_security(PFILE_OBJECT FileObject
, SECURITY_DESCRIPTOR
* relsd
, ULONG
* buflen
, SECURITY_INFORMATION flags
) {
555 fcb
* fcb
= FileObject
->FsContext
;
556 ccb
* ccb
= FileObject
->FsContext2
;
557 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
560 if (fileref
&& fileref
->parent
)
561 fcb
= fileref
->parent
->fcb
;
563 ERR("could not get parent fcb for stream\n");
564 return STATUS_INTERNAL_ERROR
;
568 // Why (void**)? Is this a bug in mingw?
569 Status
= SeQuerySecurityDescriptorInfo(&flags
, relsd
, buflen
, (void**)&fcb
->sd
);
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
);
579 _Dispatch_type_(IRP_MJ_QUERY_SECURITY
)
580 _Function_class_(DRIVER_DISPATCH
)
581 NTSTATUS
drv_query_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
583 SECURITY_DESCRIPTOR
* sd
;
584 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
585 device_extension
* Vcb
= DeviceObject
->DeviceExtension
;
588 PFILE_OBJECT FileObject
= IrpSp
->FileObject
;
589 ccb
* ccb
= FileObject
? FileObject
->FsContext2
: NULL
;
591 FsRtlEnterFileSystem();
593 TRACE("query security\n");
595 top_level
= is_top_level(Irp
);
597 if (Vcb
&& Vcb
->type
== VCB_TYPE_VOLUME
) {
598 Status
= vol_query_security(DeviceObject
, Irp
);
600 } else if (!Vcb
|| Vcb
->type
!= VCB_TYPE_FS
) {
601 Status
= STATUS_INVALID_PARAMETER
;
607 Status
= STATUS_INVALID_PARAMETER
;
611 if (Irp
->RequestorMode
== UserMode
&& !(ccb
->access
& READ_CONTROL
)) {
612 WARN("insufficient permissions\n");
613 Status
= STATUS_ACCESS_DENIED
;
617 Status
= STATUS_SUCCESS
;
619 Irp
->IoStatus
.Information
= 0;
621 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& OWNER_SECURITY_INFORMATION
)
622 TRACE("OWNER_SECURITY_INFORMATION\n");
624 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& GROUP_SECURITY_INFORMATION
)
625 TRACE("GROUP_SECURITY_INFORMATION\n");
627 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& DACL_SECURITY_INFORMATION
)
628 TRACE("DACL_SECURITY_INFORMATION\n");
630 if (IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
& SACL_SECURITY_INFORMATION
)
631 TRACE("SACL_SECURITY_INFORMATION\n");
633 TRACE("length = %u\n", IrpSp
->Parameters
.QuerySecurity
.Length
);
635 sd
= map_user_buffer(Irp
, NormalPagePriority
);
636 TRACE("sd = %p\n", sd
);
638 if (Irp
->MdlAddress
&& !sd
) {
639 ERR("MmGetSystemAddressForMdlSafe returned NULL\n");
640 Status
= STATUS_INSUFFICIENT_RESOURCES
;
644 buflen
= IrpSp
->Parameters
.QuerySecurity
.Length
;
646 Status
= get_file_security(IrpSp
->FileObject
, sd
, &buflen
, IrpSp
->Parameters
.QuerySecurity
.SecurityInformation
);
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
;
654 Irp
->IoStatus
.Information
= 0;
657 TRACE("Irp->IoStatus.Information = %u\n", Irp
->IoStatus
.Information
);
659 Irp
->IoStatus
.Status
= Status
;
661 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
664 IoSetTopLevelIrp(NULL
);
666 TRACE("returning %08x\n", Status
);
668 FsRtlExitFileSystem();
673 static NTSTATUS
set_file_security(device_extension
* Vcb
, PFILE_OBJECT FileObject
, SECURITY_DESCRIPTOR
* sd
, PSECURITY_INFORMATION flags
, PIRP Irp
) {
675 fcb
* fcb
= FileObject
->FsContext
;
676 ccb
* ccb
= FileObject
->FsContext2
;
677 file_ref
* fileref
= ccb
? ccb
->fileref
: NULL
;
678 SECURITY_DESCRIPTOR
* oldsd
;
682 TRACE("(%p, %p, %p, %x)\n", Vcb
, FileObject
, sd
, *flags
);
685 return STATUS_MEDIA_WRITE_PROTECTED
;
688 if (fileref
&& fileref
->parent
)
689 fcb
= fileref
->parent
->fcb
;
691 ERR("could not find parent fcb for stream\n");
692 return STATUS_INTERNAL_ERROR
;
697 return STATUS_INVALID_PARAMETER
;
699 ExAcquireResourceExclusiveLite(fcb
->Header
.Resource
, TRUE
);
701 if (is_subvol_readonly(fcb
->subvol
, Irp
)) {
702 Status
= STATUS_ACCESS_DENIED
;
708 Status
= SeSetSecurityDescriptorInfo(NULL
, flags
, sd
, (void**)&fcb
->sd
, PagedPool
, IoGetFileObjectGenericMapping());
710 if (!NT_SUCCESS(Status
)) {
711 ERR("SeSetSecurityDescriptorInfo returned %08x\n", Status
);
717 KeQuerySystemTime(&time
);
718 win_time_to_unix(time
, &now
);
720 fcb
->inode_item
.transid
= Vcb
->superblock
.generation
;
722 if (!ccb
->user_set_change_time
)
723 fcb
->inode_item
.st_ctime
= now
;
725 fcb
->inode_item
.sequence
++;
727 fcb
->sd_dirty
= TRUE
;
728 fcb
->sd_deleted
= FALSE
;
729 fcb
->inode_item_changed
= TRUE
;
731 fcb
->subvol
->root_item
.ctransid
= Vcb
->superblock
.generation
;
732 fcb
->subvol
->root_item
.ctime
= now
;
736 send_notification_fcb(fileref
, FILE_NOTIFY_CHANGE_SECURITY
, FILE_ACTION_MODIFIED
, NULL
);
739 ExReleaseResourceLite(fcb
->Header
.Resource
);
744 _Dispatch_type_(IRP_MJ_SET_SECURITY
)
745 _Function_class_(DRIVER_DISPATCH
)
746 NTSTATUS
drv_set_security(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
) {
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;
755 FsRtlEnterFileSystem();
757 TRACE("set security\n");
759 top_level
= is_top_level(Irp
);
761 if (Vcb
&& Vcb
->type
== VCB_TYPE_VOLUME
) {
762 Status
= vol_set_security(DeviceObject
, Irp
);
764 } else if (!Vcb
|| Vcb
->type
!= VCB_TYPE_FS
) {
765 Status
= STATUS_INVALID_PARAMETER
;
771 Status
= STATUS_INVALID_PARAMETER
;
775 Status
= STATUS_SUCCESS
;
777 Irp
->IoStatus
.Information
= 0;
779 if (IrpSp
->Parameters
.SetSecurity
.SecurityInformation
& OWNER_SECURITY_INFORMATION
) {
780 TRACE("OWNER_SECURITY_INFORMATION\n");
781 access_req
|= WRITE_OWNER
;
784 if (IrpSp
->Parameters
.SetSecurity
.SecurityInformation
& GROUP_SECURITY_INFORMATION
) {
785 TRACE("GROUP_SECURITY_INFORMATION\n");
786 access_req
|= WRITE_OWNER
;
789 if (IrpSp
->Parameters
.SetSecurity
.SecurityInformation
& DACL_SECURITY_INFORMATION
) {
790 TRACE("DACL_SECURITY_INFORMATION\n");
791 access_req
|= WRITE_DAC
;
794 if (IrpSp
->Parameters
.SetSecurity
.SecurityInformation
& SACL_SECURITY_INFORMATION
) {
795 TRACE("SACL_SECURITY_INFORMATION\n");
796 access_req
|= ACCESS_SYSTEM_SECURITY
;
799 if (Irp
->RequestorMode
== UserMode
&& (ccb
->access
& access_req
) != access_req
) {
800 Status
= STATUS_ACCESS_DENIED
;
801 WARN("insufficient privileges\n");
805 Status
= set_file_security(DeviceObject
->DeviceExtension
, FileObject
, IrpSp
->Parameters
.SetSecurity
.SecurityDescriptor
,
806 &IrpSp
->Parameters
.SetSecurity
.SecurityInformation
, Irp
);
809 Irp
->IoStatus
.Status
= Status
;
811 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
813 TRACE("returning %08x\n", Status
);
816 IoSetTopLevelIrp(NULL
);
818 FsRtlExitFileSystem();
823 static BOOL
search_for_gid(fcb
* fcb
, PSID sid
) {
826 le
= gid_map_list
.Flink
;
827 while (le
!= &gid_map_list
) {
828 gid_map
* gm
= CONTAINING_RECORD(le
, gid_map
, listentry
);
830 if (RtlEqualSid(sid
, gm
->sid
)) {
831 fcb
->inode_item
.st_gid
= gm
->gid
;
841 void find_gid(struct _fcb
* fcb
, struct _fcb
* parfcb
, PSECURITY_SUBJECT_CONTEXT subjcont
) {
844 TOKEN_PRIMARY_GROUP
* tpg
;
847 if (parfcb
&& parfcb
->inode_item
.st_mode
& S_ISGID
) {
848 fcb
->inode_item
.st_gid
= parfcb
->inode_item
.st_gid
;
852 ExAcquireResourceSharedLite(&mapping_lock
, TRUE
);
854 if (!subjcont
|| !subjcont
->PrimaryToken
|| IsListEmpty(&gid_map_list
)) {
855 ExReleaseResourceLite(&mapping_lock
);
859 Status
= SeQueryInformationToken(subjcont
->PrimaryToken
, TokenOwner
, (void**)&to
);
860 if (!NT_SUCCESS(Status
))
861 ERR("SeQueryInformationToken returned %08x\n", Status
);
863 if (search_for_gid(fcb
, to
->Owner
)) {
864 ExReleaseResourceLite(&mapping_lock
);
872 Status
= SeQueryInformationToken(subjcont
->PrimaryToken
, TokenPrimaryGroup
, (void**)&tpg
);
873 if (!NT_SUCCESS(Status
))
874 ERR("SeQueryInformationToken returned %08x\n", Status
);
876 if (search_for_gid(fcb
, tpg
->PrimaryGroup
)) {
877 ExReleaseResourceLite(&mapping_lock
);
885 Status
= SeQueryInformationToken(subjcont
->PrimaryToken
, TokenGroups
, (void**)&tg
);
886 if (!NT_SUCCESS(Status
))
887 ERR("SeQueryInformationToken returned %08x\n", Status
);
891 for (i
= 0; i
< tg
->GroupCount
; i
++) {
892 if (search_for_gid(fcb
, tg
->Groups
[i
].Sid
)) {
893 ExReleaseResourceLite(&mapping_lock
);
902 ExReleaseResourceLite(&mapping_lock
);
905 NTSTATUS
fcb_get_new_sd(fcb
* fcb
, file_ref
* parfileref
, ACCESS_STATE
* as
) {
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
);
913 if (!NT_SUCCESS(Status
)) {
914 ERR("SeAssignSecurityEx returned %08x\n", Status
);
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
;
923 fcb
->inode_item
.st_uid
= sid_to_uid(owner
);
926 find_gid(fcb
, parfileref
? parfileref
->fcb
: NULL
, &as
->SubjectSecurityContext
);
928 return STATUS_SUCCESS
;