@@ -52,34 +52,40 @@ mod impl_ {
52
52
53
53
#[ cfg( windows) ]
54
54
mod impl_ {
55
- use std:: path:: Path ;
56
-
57
- fn err ( msg : impl Into < String > ) -> std:: io:: Error {
58
- std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , msg. into ( ) )
55
+ use std:: {
56
+ io,
57
+ mem:: MaybeUninit ,
58
+ os:: windows:: io:: { FromRawHandle as _, OwnedHandle } ,
59
+ path:: Path ,
60
+ ptr,
61
+ } ;
62
+
63
+ macro_rules! error {
64
+ ( $msg: expr) => { {
65
+ let inner = io:: Error :: last_os_error( ) ;
66
+ error!( inner, $msg) ;
67
+ } } ;
68
+ ( $inner: expr, $msg: expr) => { {
69
+ return Err ( io:: Error :: new( $inner. kind( ) , $msg) ) ;
70
+ } } ;
59
71
}
60
72
61
- pub fn is_path_owned_by_current_user ( path : & Path ) -> std:: io:: Result < bool > {
62
- use windows:: {
63
- core:: { Error , PCWSTR } ,
64
- Win32 :: {
65
- Foundation :: { CloseHandle , LocalFree , BOOL , HANDLE , HLOCAL , PSID } ,
66
- Security :: {
67
- Authorization :: { GetNamedSecurityInfoW , SE_FILE_OBJECT } ,
68
- CheckTokenMembership , EqualSid , GetTokenInformation , IsWellKnownSid , TokenOwner ,
69
- WinBuiltinAdministratorsSid , OWNER_SECURITY_INFORMATION , PSECURITY_DESCRIPTOR , TOKEN_OWNER ,
70
- TOKEN_QUERY ,
71
- } ,
72
- System :: Threading :: { GetCurrentProcess , GetCurrentThread , OpenProcessToken , OpenThreadToken } ,
73
+ pub fn is_path_owned_by_current_user ( path : & Path ) -> io:: Result < bool > {
74
+ use windows_sys:: Win32 :: {
75
+ Foundation :: { GetLastError , LocalFree , ERROR_INSUFFICIENT_BUFFER , ERROR_SUCCESS } ,
76
+ Security :: {
77
+ Authorization :: { GetNamedSecurityInfoW , SE_FILE_OBJECT } ,
78
+ CheckTokenMembership , EqualSid , GetTokenInformation , IsWellKnownSid , TokenOwner ,
79
+ WinBuiltinAdministratorsSid , OWNER_SECURITY_INFORMATION , PSECURITY_DESCRIPTOR , TOKEN_OWNER ,
80
+ TOKEN_QUERY ,
73
81
} ,
82
+ System :: Threading :: { GetCurrentProcess , GetCurrentThread , OpenProcessToken , OpenThreadToken } ,
74
83
} ;
75
84
76
- let mut err_msg = None ;
77
- let mut is_owned = false ;
78
-
79
85
if !path. exists ( ) {
80
- return Err ( std :: io:: Error :: new (
81
- std :: io:: ErrorKind :: NotFound ,
82
- format ! ( "{:?} does not exist." , path ) ,
86
+ return Err ( io:: Error :: new (
87
+ io:: ErrorKind :: NotFound ,
88
+ format ! ( "{path :?} does not exist." ) ,
83
89
) ) ;
84
90
}
85
91
@@ -92,82 +98,106 @@ mod impl_ {
92
98
93
99
#[ allow( unsafe_code) ]
94
100
unsafe {
95
- let mut folder_owner = PSID :: default ( ) ;
96
- let mut pdescriptor = PSECURITY_DESCRIPTOR :: default ( ) ;
97
- let result = GetNamedSecurityInfoW (
98
- PCWSTR ( to_wide_path ( path) . as_ptr ( ) ) ,
99
- SE_FILE_OBJECT ,
100
- OWNER_SECURITY_INFORMATION ,
101
- Some ( & mut folder_owner) ,
102
- None ,
103
- None ,
104
- None ,
105
- & mut pdescriptor,
106
- ) ;
107
-
108
- // Workaround for https://github.com/microsoft/win32metadata/issues/884
109
- if result. is_ok ( ) {
110
- let mut token = HANDLE :: default ( ) ;
101
+ let ( folder_owner, descriptor) = {
102
+ let mut folder_owner = MaybeUninit :: uninit ( ) ;
103
+ let mut pdescriptor = MaybeUninit :: uninit ( ) ;
104
+ let result = GetNamedSecurityInfoW (
105
+ to_wide_path ( path) . as_ptr ( ) ,
106
+ SE_FILE_OBJECT ,
107
+ OWNER_SECURITY_INFORMATION ,
108
+ folder_owner. as_mut_ptr ( ) ,
109
+ ptr:: null_mut ( ) ,
110
+ ptr:: null_mut ( ) ,
111
+ ptr:: null_mut ( ) ,
112
+ pdescriptor. as_mut_ptr ( ) ,
113
+ ) ;
114
+
115
+ if result != ERROR_SUCCESS {
116
+ let inner = io:: Error :: from_raw_os_error ( result as _ ) ;
117
+ error ! (
118
+ inner,
119
+ format!(
120
+ "Couldn't get security information for path '{}' with err {inner}" ,
121
+ path. display( )
122
+ )
123
+ ) ;
124
+ }
125
+
126
+ ( folder_owner. assume_init ( ) , pdescriptor. assume_init ( ) )
127
+ } ;
128
+
129
+ struct Descriptor ( PSECURITY_DESCRIPTOR ) ;
130
+
131
+ impl Drop for Descriptor {
132
+ fn drop ( & mut self ) {
133
+ #[ allow( unsafe_code) ]
134
+ // SAFETY: syscall only invoked if we have a valid descriptor
135
+ unsafe {
136
+ LocalFree ( self . 0 as _ ) ;
137
+ }
138
+ }
139
+ }
140
+
141
+ let _descriptor = Descriptor ( descriptor) ;
142
+
143
+ let token = {
144
+ let mut token = MaybeUninit :: uninit ( ) ;
145
+
111
146
// Use the current thread token if possible, otherwise open the process token
112
- OpenThreadToken ( GetCurrentThread ( ) , TOKEN_QUERY , true , & mut token)
113
- . or_else ( |_| OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_QUERY , & mut token) ) ?;
114
-
115
- let mut buffer_size = 0 ;
116
- let mut buffer = Vec :: < u8 > :: new ( ) ;
117
- GetTokenInformation ( token, TokenOwner , None , 0 , & mut buffer_size) . ok ( ) ;
118
- if buffer_size != 0 {
119
- buffer. resize ( buffer_size as usize , 0 ) ;
120
- match GetTokenInformation (
147
+ if OpenThreadToken ( GetCurrentThread ( ) , TOKEN_QUERY , 1 , token. as_mut_ptr ( ) ) == 0
148
+ && OpenProcessToken ( GetCurrentProcess ( ) , TOKEN_QUERY , token. as_mut_ptr ( ) ) == 0
149
+ {
150
+ error ! ( "Couldn't acquire thread or process token" ) ;
151
+ }
152
+ token. assume_init ( )
153
+ } ;
154
+
155
+ let _owned_token = OwnedHandle :: from_raw_handle ( token as _ ) ;
156
+
157
+ let buf = ' token_buf: {
158
+ let mut buffer_size = 36 ;
159
+ let mut heap_buf = vec ! [ 0 ; 36 ] ;
160
+
161
+ loop {
162
+ if GetTokenInformation (
121
163
token,
122
164
TokenOwner ,
123
- Some ( buffer . as_mut_ptr ( ) as * mut std :: ffi :: c_void ) ,
124
- buffer_size ,
165
+ heap_buf . as_mut_ptr ( ) . cast ( ) ,
166
+ heap_buf . len ( ) as _ ,
125
167
& mut buffer_size,
126
- ) {
127
- Ok ( ( ) ) => {
128
- let token_owner = buffer. as_ptr ( ) as * const TOKEN_OWNER ;
129
- let token_owner = ( * token_owner) . Owner ;
130
-
131
- is_owned = EqualSid ( folder_owner, token_owner) . is_ok ( ) ;
132
-
133
- // Admin-group owned folders are considered owned by the current user, if they are in the admin group
134
- if !is_owned && IsWellKnownSid ( token_owner, WinBuiltinAdministratorsSid ) . as_bool ( ) {
135
- let mut is_member = BOOL :: default ( ) ;
136
- // TODO: reuse the handle
137
- match CheckTokenMembership ( HANDLE :: default ( ) , token_owner, & mut is_member) {
138
- Err ( e) => {
139
- err_msg = Some ( format ! ( "Couldn't check if user is an administrator: {}" , e) )
140
- }
141
- Ok ( ( ) ) => is_owned = is_member. as_bool ( ) ,
142
- }
143
- }
144
- }
145
- Err ( err) => {
146
- err_msg =
147
- format ! ( "Couldn't get actual token information for current process with err: {err}" , )
148
- . into ( ) ;
149
- }
168
+ ) != 0
169
+ {
170
+ break ' token_buf heap_buf;
150
171
}
151
- } else {
152
- err_msg = format ! (
153
- "Couldn't get token information size info for current process with err: {}" ,
154
- Error :: from_win32 ( )
155
- )
156
- . into ( ) ;
172
+
173
+ if GetLastError ( ) != ERROR_INSUFFICIENT_BUFFER {
174
+ error ! ( "Couldn't acquire token ownership" ) ;
175
+ }
176
+
177
+ heap_buf . resize ( buffer_size as _ , 0 ) ;
157
178
}
158
- CloseHandle ( token) ?;
159
- } else {
160
- err_msg = format ! (
161
- "Couldn't get security information for path '{}' with err {}" ,
162
- path. display( ) ,
163
- Error :: from_win32( )
164
- )
165
- . into ( ) ;
179
+ } ;
180
+
181
+ let token_owner = ( * buf. as_ptr ( ) . cast :: < TOKEN_OWNER > ( ) ) . Owner ;
182
+
183
+ // If the current user is the owner of the parent folder then they also
184
+ // own this file
185
+ if EqualSid ( folder_owner, token_owner) != 0 {
186
+ return Ok ( true ) ;
187
+ }
188
+
189
+ // Admin-group owned folders are considered owned by the current user, if they are in the admin group
190
+ if IsWellKnownSid ( token_owner, WinBuiltinAdministratorsSid ) == 0 {
191
+ return Ok ( false ) ;
166
192
}
167
- LocalFree ( HLOCAL ( pdescriptor. 0 ) ) . ok ( ) ;
168
- }
169
193
170
- err_msg. map ( |msg| Err ( err ( msg) ) ) . unwrap_or ( Ok ( is_owned) )
194
+ let mut is_member = 0 ;
195
+ if CheckTokenMembership ( 0 , token_owner, & mut is_member) == 0 {
196
+ error ! ( "Couldn't check if user is an administrator" ) ;
197
+ }
198
+
199
+ Ok ( is_member != 0 )
200
+ }
171
201
}
172
202
173
203
fn to_wide_path ( path : impl AsRef < Path > ) -> Vec < u16 > {
0 commit comments