Skip to content

Commit 39e3748

Browse files
codexByron
andcommitted
fix: make gix-sec identity check on Windows similar to Git for Windows
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
1 parent e51c40b commit 39e3748

1 file changed

Lines changed: 69 additions & 35 deletions

File tree

‎gix-sec/src/identity.rs‎

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ mod impl_ {
6363
#[cfg(windows)]
6464
mod impl_ {
6565
use std::{
66-
io,
66+
io, mem,
6767
mem::MaybeUninit,
68-
os::windows::io::{FromRawHandle as _, OwnedHandle},
68+
os::windows::io::{AsRawHandle as _, FromRawHandle as _, OwnedHandle},
6969
path::Path,
7070
ptr,
7171
};
@@ -80,14 +80,46 @@ mod impl_ {
8080
}};
8181
}
8282

83+
fn token_information(token: windows_sys::Win32::Foundation::HANDLE, class: i32) -> io::Result<Vec<u8>> {
84+
use windows_sys::Win32::{
85+
Foundation::{GetLastError, ERROR_INSUFFICIENT_BUFFER},
86+
Security::GetTokenInformation,
87+
};
88+
89+
#[allow(unsafe_code)]
90+
unsafe {
91+
let mut buffer_size = 36;
92+
let mut heap_buf = vec![0; 36];
93+
94+
loop {
95+
if GetTokenInformation(
96+
token,
97+
class,
98+
heap_buf.as_mut_ptr().cast(),
99+
heap_buf.len() as _,
100+
&mut buffer_size,
101+
) != 0
102+
{
103+
return Ok(heap_buf);
104+
}
105+
106+
if GetLastError() != ERROR_INSUFFICIENT_BUFFER {
107+
error!("Couldn't acquire token information");
108+
}
109+
110+
heap_buf.resize(buffer_size as _, 0);
111+
}
112+
}
113+
}
114+
83115
pub fn is_path_owned_by_current_user(path: &Path) -> io::Result<bool> {
84116
use windows_sys::Win32::{
85-
Foundation::{GetLastError, LocalFree, ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_FUNCTION, ERROR_SUCCESS},
117+
Foundation::{LocalFree, ERROR_INVALID_FUNCTION, ERROR_SUCCESS},
86118
Security::{
87119
Authorization::{GetNamedSecurityInfoW, SE_FILE_OBJECT},
88-
CheckTokenMembership, EqualSid, GetTokenInformation, IsWellKnownSid, TokenOwner,
89-
WinBuiltinAdministratorsSid, OWNER_SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, TOKEN_OWNER,
90-
TOKEN_QUERY,
120+
CheckTokenMembership, EqualSid, IsWellKnownSid, TokenElevationType, TokenElevationTypeLimited,
121+
TokenLinkedToken, TokenUser, WinBuiltinAdministratorsSid, OWNER_SECURITY_INFORMATION,
122+
PSECURITY_DESCRIPTOR, TOKEN_ELEVATION_TYPE, TOKEN_LINKED_TOKEN, TOKEN_QUERY, TOKEN_USER,
91123
},
92124
System::Threading::{GetCurrentProcess, GetCurrentThread, OpenProcessToken, OpenThreadToken},
93125
};
@@ -169,46 +201,48 @@ mod impl_ {
169201

170202
let _owned_token = OwnedHandle::from_raw_handle(token as _);
171203

172-
let buf = 'token_buf: {
173-
let mut buffer_size = 36;
174-
let mut heap_buf = vec![0; 36];
175-
176-
loop {
177-
if GetTokenInformation(
178-
token,
179-
TokenOwner,
180-
heap_buf.as_mut_ptr().cast(),
181-
heap_buf.len() as _,
182-
&mut buffer_size,
183-
) != 0
184-
{
185-
break 'token_buf heap_buf;
186-
}
204+
let user_info = token_information(token, TokenUser)?;
205+
let token_user = (*user_info.as_ptr().cast::<TOKEN_USER>()).User.Sid;
187206

188-
if GetLastError() != ERROR_INSUFFICIENT_BUFFER {
189-
error!("Couldn't acquire token ownership");
190-
}
207+
if EqualSid(folder_owner, token_user) != 0 {
208+
return Ok(true);
209+
}
191210

192-
heap_buf.resize(buffer_size as _, 0);
193-
}
194-
};
211+
// Admin-group owned folders are considered owned by the current user, if they are in the admin group.
212+
if IsWellKnownSid(folder_owner, WinBuiltinAdministratorsSid) == 0 {
213+
return Ok(false);
214+
}
195215

196-
let token_owner = (*buf.as_ptr().cast::<TOKEN_OWNER>()).Owner;
216+
let mut is_member = 0;
217+
if CheckTokenMembership(std::ptr::null_mut(), folder_owner, &mut is_member) == 0 {
218+
error!("Couldn't check if user is an administrator");
219+
}
197220

198-
// If the current user is the owner of the parent folder then they also
199-
// own this file
200-
if EqualSid(folder_owner, token_owner) != 0 {
221+
if is_member != 0 {
201222
return Ok(true);
202223
}
203224

204-
// Admin-group owned folders are considered owned by the current user, if they are in the admin group
205-
if IsWellKnownSid(token_owner, WinBuiltinAdministratorsSid) == 0 {
225+
let mut elevation_type = TokenElevationTypeLimited;
226+
let mut elevation_type_size = 0;
227+
if windows_sys::Win32::Security::GetTokenInformation(
228+
token,
229+
TokenElevationType,
230+
(&mut elevation_type as *mut TOKEN_ELEVATION_TYPE).cast(),
231+
mem::size_of::<TOKEN_ELEVATION_TYPE>() as u32,
232+
&mut elevation_type_size,
233+
) == 0
234+
|| elevation_type != TokenElevationTypeLimited
235+
{
206236
return Ok(false);
207237
}
208238

239+
let linked_token_info = token_information(token, TokenLinkedToken)?;
240+
let linked_token = (*linked_token_info.as_ptr().cast::<TOKEN_LINKED_TOKEN>()).LinkedToken;
241+
let linked_token = OwnedHandle::from_raw_handle(linked_token as _);
242+
209243
let mut is_member = 0;
210-
if CheckTokenMembership(std::ptr::null_mut(), token_owner, &mut is_member) == 0 {
211-
error!("Couldn't check if user is an administrator");
244+
if CheckTokenMembership(linked_token.as_raw_handle() as _, folder_owner, &mut is_member) == 0 {
245+
error!("Couldn't check if elevated user is an administrator");
212246
}
213247

214248
Ok(is_member != 0)

0 commit comments

Comments
 (0)