|
1 | 1 | use crate::{ |
2 | 2 | chunk::{self, AcePlatform, Identifier, OwnerType}, |
3 | 3 | utils::os::windows::{ |
4 | | - fs::open_read_metadata, |
| 4 | + fs::{open_read_metadata, open_write_dacl}, |
5 | 5 | security::{SecurityDescriptor, Sid, SidType}, |
6 | 6 | }, |
7 | 7 | }; |
8 | 8 | use field_offset::offset_of; |
9 | 9 | use std::{io, mem, path::Path, ptr::null_mut}; |
| 10 | +use windows::Win32::Foundation::HANDLE; |
10 | 11 | use windows::Win32::Security::{ |
11 | 12 | ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, ACE_FLAGS, ACE_HEADER, ACL as Win32ACL, ACL_REVISION_DS, |
12 | 13 | AddAccessAllowedAceEx, AddAccessDeniedAceEx, CONTAINER_INHERIT_ACE, GetAce, INHERIT_ONLY_ACE, |
@@ -41,6 +42,20 @@ pub fn get_facl<P: AsRef<Path>>(path: P) -> io::Result<chunk::Acl> { |
41 | 42 | }) |
42 | 43 | } |
43 | 44 |
|
| 45 | +pub fn set_facl_nofollow<P: AsRef<Path>>(path: P, ace_list: chunk::Acl) -> io::Result<()> { |
| 46 | + let path = path.as_ref(); |
| 47 | + let handle = open_write_dacl(path, false)?; |
| 48 | + let acl = ACL::try_from_handle(handle.raw(), path)?; |
| 49 | + let group_sid = acl.security_descriptor.group_sid()?; |
| 50 | + let owner_sid = acl.security_descriptor.owner_sid()?; |
| 51 | + let acl_entries = ace_list |
| 52 | + .entries |
| 53 | + .into_iter() |
| 54 | + .map(|it| it.into_acl_entry_with(&owner_sid, &group_sid)) |
| 55 | + .collect::<Vec<_>>(); |
| 56 | + acl.set_d_acl_by_handle(handle.raw(), &acl_entries) |
| 57 | +} |
| 58 | + |
44 | 59 | pub fn get_facl_nofollow<P: AsRef<Path>>(path: P) -> io::Result<chunk::Acl> { |
45 | 60 | let acl = ACL::try_from_nofollow(path.as_ref())?; |
46 | 61 | let ace_list = acl.get_d_acl()?; |
@@ -71,6 +86,12 @@ impl ACL { |
71 | 86 | }) |
72 | 87 | } |
73 | 88 |
|
| 89 | + pub fn try_from_handle(handle: HANDLE, path: &Path) -> io::Result<Self> { |
| 90 | + Ok(Self { |
| 91 | + security_descriptor: SecurityDescriptor::try_from_handle(handle, path)?, |
| 92 | + }) |
| 93 | + } |
| 94 | + |
74 | 95 | pub fn get_d_acl(&self) -> io::Result<Vec<ACLEntry>> { |
75 | 96 | let mut result = Vec::new(); |
76 | 97 | let p_acl = self.security_descriptor.p_dacl; |
@@ -128,37 +149,47 @@ impl ACL { |
128 | 149 | } |
129 | 150 |
|
130 | 151 | pub fn set_d_acl(&self, acl_entries: &[ACLEntry]) -> io::Result<()> { |
131 | | - let acl_size = acl_entries.iter().map(|it| it.size as usize).sum::<usize>() |
132 | | - + mem::size_of::<Win32ACL>(); |
133 | | - let mut new_acl_buffer = Vec::<u8>::with_capacity(acl_size); |
134 | | - let new_acl = new_acl_buffer.as_mut_ptr(); |
135 | | - unsafe { InitializeAcl(new_acl as _, acl_size as u32, ACL_REVISION_DS) }?; |
136 | | - for ace in acl_entries { |
137 | | - match ace.ace_type { |
138 | | - AceType::AccessAllow => unsafe { |
139 | | - AddAccessAllowedAceEx( |
140 | | - new_acl as _, |
141 | | - ACL_REVISION_DS, |
142 | | - ACE_FLAGS(ace.flags as u32), |
143 | | - ace.mask, |
144 | | - ace.sid.as_psid(), |
145 | | - ) |
146 | | - }, |
147 | | - AceType::AccessDeny => unsafe { |
148 | | - AddAccessDeniedAceEx( |
149 | | - new_acl as _, |
150 | | - ACL_REVISION_DS, |
151 | | - ACE_FLAGS(ace.flags as u32), |
152 | | - ace.mask, |
153 | | - ace.sid.as_psid(), |
154 | | - ) |
155 | | - }, |
156 | | - AceType::Unknown(n) => return Err(io::Error::other(format!("{}", n))), |
157 | | - }?; |
158 | | - } |
| 152 | + let buffer = build_acl_buffer(acl_entries)?; |
159 | 153 | self.security_descriptor |
160 | | - .apply(None, None, Some(new_acl as _)) |
| 154 | + .apply(None, None, Some(buffer.as_ptr() as _)) |
| 155 | + } |
| 156 | + |
| 157 | + pub fn set_d_acl_by_handle(&self, handle: HANDLE, acl_entries: &[ACLEntry]) -> io::Result<()> { |
| 158 | + let buffer = build_acl_buffer(acl_entries)?; |
| 159 | + SecurityDescriptor::apply_by_handle(handle, None, None, Some(buffer.as_ptr() as _)) |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +fn build_acl_buffer(acl_entries: &[ACLEntry]) -> io::Result<Vec<u8>> { |
| 164 | + let acl_size = |
| 165 | + acl_entries.iter().map(|it| it.size as usize).sum::<usize>() + mem::size_of::<Win32ACL>(); |
| 166 | + let mut buffer = Vec::<u8>::with_capacity(acl_size); |
| 167 | + let ptr = buffer.as_mut_ptr(); |
| 168 | + unsafe { InitializeAcl(ptr as _, acl_size as u32, ACL_REVISION_DS) }?; |
| 169 | + for ace in acl_entries { |
| 170 | + match ace.ace_type { |
| 171 | + AceType::AccessAllow => unsafe { |
| 172 | + AddAccessAllowedAceEx( |
| 173 | + ptr as _, |
| 174 | + ACL_REVISION_DS, |
| 175 | + ACE_FLAGS(ace.flags as u32), |
| 176 | + ace.mask, |
| 177 | + ace.sid.as_psid(), |
| 178 | + ) |
| 179 | + }, |
| 180 | + AceType::AccessDeny => unsafe { |
| 181 | + AddAccessDeniedAceEx( |
| 182 | + ptr as _, |
| 183 | + ACL_REVISION_DS, |
| 184 | + ACE_FLAGS(ace.flags as u32), |
| 185 | + ace.mask, |
| 186 | + ace.sid.as_psid(), |
| 187 | + ) |
| 188 | + }, |
| 189 | + AceType::Unknown(n) => return Err(io::Error::other(format!("{}", n))), |
| 190 | + }?; |
161 | 191 | } |
| 192 | + Ok(buffer) |
162 | 193 | } |
163 | 194 |
|
164 | 195 | #[derive(Clone, Copy, Debug, PartialEq)] |
|
0 commit comments