@@ -34,6 +34,7 @@ use windows_sys::Win32::Storage::FileSystem::FILE_ALL_ACCESS;
3434use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_APPEND_DATA ;
3535use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_ATTRIBUTE_NORMAL ;
3636use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_FLAG_BACKUP_SEMANTICS ;
37+ use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_DELETE_CHILD ;
3738use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_GENERIC_EXECUTE ;
3839use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_GENERIC_READ ;
3940use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_GENERIC_WRITE ;
@@ -45,12 +46,16 @@ use windows_sys::Win32::Storage::FileSystem::FILE_WRITE_DATA;
4546use windows_sys:: Win32 :: Storage :: FileSystem :: FILE_WRITE_EA ;
4647use windows_sys:: Win32 :: Storage :: FileSystem :: OPEN_EXISTING ;
4748use windows_sys:: Win32 :: Storage :: FileSystem :: READ_CONTROL ;
49+ use windows_sys:: Win32 :: Storage :: FileSystem :: DELETE ;
4850const SE_KERNEL_OBJECT : u32 = 6 ;
4951const INHERIT_ONLY_ACE : u8 = 0x08 ;
5052const GENERIC_WRITE_MASK : u32 = 0x4000_0000 ;
5153const DENY_ACCESS : i32 = 3 ;
5254
5355/// Fetch DACL via handle-based query; caller must LocalFree the returned SD.
56+ ///
57+ /// # Safety
58+ /// Caller must free the returned security descriptor with `LocalFree` and pass an existing path.
5459pub unsafe fn fetch_dacl_handle ( path : & Path ) -> Result < ( * mut ACL , * mut c_void ) > {
5560 let wpath = to_wide ( path) ;
5661 let h = CreateFileW (
@@ -88,11 +93,13 @@ pub unsafe fn fetch_dacl_handle(path: &Path) -> Result<(*mut ACL, *mut c_void)>
8893 Ok ( ( p_dacl, p_sd) )
8994}
9095
91- /// Fast mask-based check: does any ACE for provided SIDs grant at least one desired bit? Skips inherit-only.
92- pub unsafe fn dacl_quick_mask_allows (
96+ /// Fast mask-based check: does an ACE for provided SIDs grant the desired mask? Skips inherit-only.
97+ /// When `require_all_bits` is true, all bits in `desired_mask` must be present; otherwise any bit suffices.
98+ pub unsafe fn dacl_mask_allows (
9399 p_dacl : * mut ACL ,
94100 psids : & [ * mut c_void ] ,
95101 desired_mask : u32 ,
102+ require_all_bits : bool ,
96103) -> bool {
97104 if p_dacl. is_null ( ) {
98105 return false ;
@@ -141,22 +148,25 @@ pub unsafe fn dacl_quick_mask_allows(
141148 let ace = & * ( p_ace as * const ACCESS_ALLOWED_ACE ) ;
142149 let mut mask = ace. Mask ;
143150 MapGenericMask ( & mut mask, & mapping) ;
144- if ( mask & desired_mask) != 0 {
151+ if ( require_all_bits && ( mask & desired_mask) == desired_mask)
152+ || ( !require_all_bits && ( mask & desired_mask) != 0 )
153+ {
145154 return true ;
146155 }
147156 }
148157 false
149158}
150159
151- /// Path-based wrapper around the quick mask check (single DACL fetch).
152- pub fn path_quick_mask_allows (
160+ /// Path-based wrapper around the mask check (single DACL fetch).
161+ pub fn path_mask_allows (
153162 path : & Path ,
154163 psids : & [ * mut c_void ] ,
155164 desired_mask : u32 ,
165+ require_all_bits : bool ,
156166) -> Result < bool > {
157167 unsafe {
158168 let ( p_dacl, sd) = fetch_dacl_handle ( path) ?;
159- let has = dacl_quick_mask_allows ( p_dacl, psids, desired_mask) ;
169+ let has = dacl_mask_allows ( p_dacl, psids, desired_mask, require_all_bits ) ;
160170 if !sd. is_null ( ) {
161171 LocalFree ( sd as HLOCAL ) ;
162172 }
@@ -326,16 +336,23 @@ pub unsafe fn dacl_effective_allows_mask(
326336}
327337
328338#[ allow( dead_code) ]
329- const WRITE_ALLOW_MASK : u32 = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE ;
339+ const WRITE_ALLOW_MASK : u32 = FILE_GENERIC_READ
340+ | FILE_GENERIC_WRITE
341+ | FILE_GENERIC_EXECUTE
342+ | DELETE
343+ | FILE_DELETE_CHILD ;
330344
331345/// Ensure all provided SIDs have a write-capable allow ACE on the path.
332346/// Returns true if any ACE was added.
347+ ///
348+ /// # Safety
349+ /// Caller must pass valid SID pointers and an existing path; free the returned security descriptor with `LocalFree`.
333350#[ allow( dead_code) ]
334351pub unsafe fn ensure_allow_write_aces ( path : & Path , sids : & [ * mut c_void ] ) -> Result < bool > {
335352 let ( p_dacl, p_sd) = fetch_dacl_handle ( path) ?;
336353 let mut entries: Vec < EXPLICIT_ACCESS_W > = Vec :: new ( ) ;
337354 for sid in sids {
338- if dacl_quick_mask_allows ( p_dacl, & [ * sid] , WRITE_ALLOW_MASK ) {
355+ if dacl_mask_allows ( p_dacl, & [ * sid] , WRITE_ALLOW_MASK , true ) {
339356 continue ;
340357 }
341358 entries. push ( EXPLICIT_ACCESS_W {
0 commit comments