Skip to content

Commit 68a7079

Browse files
Jake-ShadleByron
authored andcommitted
Replace windows with windows-sys
1 parent 5d176fc commit 68a7079

File tree

4 files changed

+129
-116
lines changed

4 files changed

+129
-116
lines changed

Diff for: .github/workflows/ci.yml

-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ jobs:
8585
- uses: taiki-e/install-action@v1
8686
with:
8787
tool: nextest
88-
version: 0.9
8988
- name: "Test (nextest)"
9089
run: cargo nextest run --all --no-fail-fast
9190

Diff for: Cargo.lock

+2-21
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: gix-sec/Cargo.toml

+7-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ doctest = false
1414

1515
[features]
1616
## Data structures implement `serde::Serialize` and `serde::Deserialize`.
17-
serde = [ "dep:serde", "bitflags/serde" ]
17+
serde = ["dep:serde", "bitflags/serde"]
1818

1919
[dependencies]
20-
serde = { version = "1.0.114", optional = true, default-features = false, features = ["std", "derive"] }
20+
serde = { version = "1.0.114", optional = true, default-features = false, features = [
21+
"std",
22+
"derive",
23+
] }
2124
bitflags = "2"
2225

2326
document-features = { version = "0.2.1", optional = true }
@@ -27,12 +30,12 @@ libc = "0.2.123"
2730

2831
[target.'cfg(windows)'.dependencies]
2932
gix-path = { version = "^0.10.3", path = "../gix-path" }
30-
windows = { version = "0.52.0", features = [
33+
windows-sys = { version = "0.52.0", features = [
3134
"Win32_Foundation",
3235
"Win32_Security_Authorization",
3336
"Win32_Storage_FileSystem",
3437
"Win32_System_Memory",
35-
"Win32_System_Threading"
38+
"Win32_System_Threading",
3639
] }
3740

3841
[dev-dependencies]

Diff for: gix-sec/src/identity.rs

+120-90
Original file line numberDiff line numberDiff line change
@@ -52,34 +52,40 @@ mod impl_ {
5252

5353
#[cfg(windows)]
5454
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+
}};
5971
}
6072

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,
7381
},
82+
System::Threading::{GetCurrentProcess, GetCurrentThread, OpenProcessToken, OpenThreadToken},
7483
};
7584

76-
let mut err_msg = None;
77-
let mut is_owned = false;
78-
7985
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."),
8389
));
8490
}
8591

@@ -92,82 +98,106 @@ mod impl_ {
9298

9399
#[allow(unsafe_code)]
94100
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+
111146
// 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(
121163
token,
122164
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 _,
125167
&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;
150171
}
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);
157178
}
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);
166192
}
167-
LocalFree(HLOCAL(pdescriptor.0)).ok();
168-
}
169193

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+
}
171201
}
172202

173203
fn to_wide_path(path: impl AsRef<Path>) -> Vec<u16> {

0 commit comments

Comments
 (0)