move winapi to windows

This commit is contained in:
Icxolu 2022-11-06 20:56:57 +01:00 committed by Abin Simon
parent f014138a0c
commit c1c8958fd0
4 changed files with 142 additions and 81 deletions

69
Cargo.lock generated
View file

@ -441,7 +441,7 @@ dependencies = [
"users",
"version_check",
"wild",
"winapi",
"windows",
"xattr",
"xdg",
"yaml-rust",
@ -1037,49 +1037,106 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.42.0",
"windows_i686_gnu 0.42.0",
"windows_i686_msvc 0.42.0",
"windows_x86_64_gnu 0.42.0",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.42.0",
]
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
"windows_aarch64_msvc 0.36.1",
"windows_i686_gnu 0.36.1",
"windows_i686_msvc 0.36.1",
"windows_x86_64_gnu 0.36.1",
"windows_x86_64_msvc 0.36.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_i686_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "xattr"
version = "0.2.2"

View file

@ -45,7 +45,7 @@ users = "0.11.*"
xattr = "0.2.*"
[target.'cfg(windows)'.dependencies]
winapi = {version = "0.3.*", features = ["aclapi", "accctrl", "winnt", "winerror", "securitybaseapi", "winbase"]}
windows = { version = "0.43.0", features = ["Win32_Foundation", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Memory"] }
[dependencies.clap]
features = ["suggestions", "color", "wrap_help"]

View file

@ -25,7 +25,7 @@ extern crate yaml_rust;
extern crate users;
#[cfg(windows)]
extern crate winapi;
extern crate windows;
mod app;
mod color;

View file

@ -1,13 +1,11 @@
use std::ffi::{OsStr, OsString};
use std::io;
use std::mem::MaybeUninit;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::path::Path;
use std::ptr::null_mut;
use winapi::ctypes::c_void;
use winapi::shared::winerror;
use winapi::um::accctrl::TRUSTEE_W;
use winapi::um::winnt;
use windows::Win32::Foundation::PSID;
use windows::Win32::Security::{self, Authorization::TRUSTEE_W, ACL};
use super::{Owner, Permissions};
@ -30,10 +28,10 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
// These pointers will be populated by GetNamedSecurityInfoW
// sd_ptr points at a new buffer that must be freed
// The others point at (opaque) things inside that buffer
let mut owner_sid_ptr = null_mut();
let mut group_sid_ptr = null_mut();
let mut dacl_ptr = null_mut();
let mut sd_ptr = null_mut();
let mut owner_sid_ptr = MaybeUninit::uninit();
let mut group_sid_ptr = MaybeUninit::uninit();
let mut dacl_ptr = MaybeUninit::uninit();
let mut sd_ptr = MaybeUninit::uninit();
// Assumptions:
// - windows_path is a null-terminated WTF-16-encoded string
@ -43,28 +41,32 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
// flags are set
// - sd_ptr must be freed with LocalFree
let error_code = unsafe {
winapi::um::aclapi::GetNamedSecurityInfoW(
windows_path.as_ptr(),
winapi::um::accctrl::SE_FILE_OBJECT,
winnt::OWNER_SECURITY_INFORMATION
| winnt::GROUP_SECURITY_INFORMATION
| winnt::DACL_SECURITY_INFORMATION,
&mut owner_sid_ptr,
&mut group_sid_ptr,
&mut dacl_ptr,
null_mut(),
&mut sd_ptr,
Security::Authorization::GetNamedSecurityInfoW(
windows::core::PCWSTR::from_raw(windows_path.as_ptr()),
Security::Authorization::SE_FILE_OBJECT,
Security::OWNER_SECURITY_INFORMATION
| Security::GROUP_SECURITY_INFORMATION
| Security::DACL_SECURITY_INFORMATION,
Some(owner_sid_ptr.as_mut_ptr()),
Some(group_sid_ptr.as_mut_ptr()),
Some(dacl_ptr.as_mut_ptr()),
None,
sd_ptr.as_mut_ptr(),
)
};
if error_code != winerror::ERROR_SUCCESS {
return Err(std::io::Error::from_raw_os_error(error_code as i32));
if error_code.is_err() {
return Err(std::io::Error::from_raw_os_error(error_code.0 as i32));
}
// Assumptions:
// - owner_sid_ptr is valid
// - group_sid_ptr is valid
// (both OK because GetNamedSecurityInfoW returned success)
let owner_sid_ptr = unsafe { owner_sid_ptr.assume_init() };
let group_sid_ptr = unsafe { group_sid_ptr.assume_init() };
let dacl_ptr = unsafe { dacl_ptr.assume_init() };
let sd_ptr = unsafe { sd_ptr.assume_init() };
let owner = match unsafe { lookup_account_sid(owner_sid_ptr) } {
Ok((n, d)) => {
@ -104,8 +106,9 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
// Assumptions: None
// "This function cannot fail"
// -- Windows Dev Center docs
let mut world_sid_len: u32 = unsafe { winapi::um::securitybaseapi::GetSidLengthRequired(1) };
let mut world_sid_len: u32 = unsafe { Security::GetSidLengthRequired(1) };
let mut world_sid = vec![0u8; world_sid_len as usize];
let world_sid_ptr = PSID(world_sid.as_mut_ptr() as *mut _);
// Assumptions:
// - world_sid_len is no larger than the number of bytes available at
@ -113,61 +116,65 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
// - world_sid is appropriately aligned (if there are strange crashes this
// might be why)
let result = unsafe {
winapi::um::securitybaseapi::CreateWellKnownSid(
winnt::WinWorldSid,
null_mut(),
world_sid.as_mut_ptr() as *mut _,
Security::CreateWellKnownSid(
Security::WinWorldSid,
PSID::default(),
world_sid_ptr,
&mut world_sid_len,
)
};
if result == 0 {
if result.ok().is_err() {
// Failed to create the SID
// Assumptions: Same as the other identical calls
unsafe {
winapi::um::winbase::LocalFree(sd_ptr);
windows::Win32::System::Memory::LocalFree(sd_ptr.0 as _);
}
// Assumptions: None (GetLastError shouldn't ever fail)
return Err(io::Error::from_raw_os_error(unsafe {
winapi::um::errhandlingapi::GetLastError()
windows::Win32::Foundation::GetLastError().0
} as i32));
}
// Assumptions:
// - xxxxx_sid_ptr are valid pointers to SIDs
// - xxxxx_trustee is only valid as long as its SID pointer is
let mut owner_trustee = unsafe { trustee_from_sid(owner_sid_ptr) };
let mut group_trustee = unsafe { trustee_from_sid(group_sid_ptr) };
let mut world_trustee = unsafe { trustee_from_sid(world_sid.as_mut_ptr() as *mut _) };
let owner_trustee = unsafe { trustee_from_sid(owner_sid_ptr) };
let group_trustee = unsafe { trustee_from_sid(group_sid_ptr) };
let world_trustee = unsafe { trustee_from_sid(world_sid_ptr) };
// Assumptions:
// - xxxxx_trustee are still valid (including underlying SID)
// - dacl_ptr is still valid
let owner_access_mask = unsafe { get_acl_access_mask(dacl_ptr as *mut _, &mut owner_trustee) }?;
let owner_access_mask = unsafe { get_acl_access_mask(dacl_ptr, &owner_trustee) }?;
let group_access_mask = unsafe { get_acl_access_mask(dacl_ptr as *mut _, &mut group_trustee) }?;
let group_access_mask = unsafe { get_acl_access_mask(dacl_ptr, &group_trustee) }?;
let world_access_mask = unsafe { get_acl_access_mask(dacl_ptr as *mut _, &mut world_trustee) }?;
let world_access_mask = unsafe { get_acl_access_mask(dacl_ptr, &world_trustee) }?;
let has_bit = |field: u32, bit: u32| field & bit != 0;
let permissions = {
use windows::Win32::Storage::FileSystem::{
FILE_ACCESS_FLAGS, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
};
let has_bit = |field: u32, bit: FILE_ACCESS_FLAGS| field & bit.0 != 0;
Permissions {
user_read: has_bit(owner_access_mask, FILE_GENERIC_READ),
user_write: has_bit(owner_access_mask, FILE_GENERIC_WRITE),
user_execute: has_bit(owner_access_mask, FILE_GENERIC_EXECUTE),
let permissions = Permissions {
user_read: has_bit(owner_access_mask, winnt::FILE_GENERIC_READ),
user_write: has_bit(owner_access_mask, winnt::FILE_GENERIC_WRITE),
user_execute: has_bit(owner_access_mask, winnt::FILE_GENERIC_EXECUTE),
group_read: has_bit(group_access_mask, FILE_GENERIC_READ),
group_write: has_bit(group_access_mask, FILE_GENERIC_WRITE),
group_execute: has_bit(group_access_mask, FILE_GENERIC_EXECUTE),
group_read: has_bit(group_access_mask, winnt::FILE_GENERIC_READ),
group_write: has_bit(group_access_mask, winnt::FILE_GENERIC_WRITE),
group_execute: has_bit(group_access_mask, winnt::FILE_GENERIC_EXECUTE),
other_read: has_bit(world_access_mask, FILE_GENERIC_READ),
other_write: has_bit(world_access_mask, FILE_GENERIC_WRITE),
other_execute: has_bit(world_access_mask, FILE_GENERIC_EXECUTE),
other_read: has_bit(world_access_mask, winnt::FILE_GENERIC_READ),
other_write: has_bit(world_access_mask, winnt::FILE_GENERIC_WRITE),
other_execute: has_bit(world_access_mask, winnt::FILE_GENERIC_EXECUTE),
sticky: false,
setuid: false,
setgid: false,
sticky: false,
setuid: false,
setgid: false,
}
};
// Assumptions:
@ -177,7 +184,7 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
// options. It's not much memory, so leaking it on failure is
// *probably* fine)
unsafe {
winapi::um::winbase::LocalFree(sd_ptr);
windows::Win32::System::Memory::LocalFree(sd_ptr.0 as _);
}
Ok((owner, permissions))
@ -190,24 +197,21 @@ pub fn get_file_data(path: &Path) -> Result<(Owner, Permissions), io::Error> {
/// - trustee_ptr points to a valid trustee data structure
/// - Both remain valid through the function call (no long-term requirement)
unsafe fn get_acl_access_mask(
acl_ptr: *mut c_void,
trustee_ptr: *mut TRUSTEE_W,
acl_ptr: *const ACL,
trustee_ptr: *const TRUSTEE_W,
) -> Result<u32, io::Error> {
let mut access_mask = 0;
// Assumptions:
// - All function assumptions
// - Result is not valid until return value is checked
let err_code = winapi::um::aclapi::GetEffectiveRightsFromAclW(
acl_ptr as *mut _,
trustee_ptr,
&mut access_mask,
);
let err_code =
Security::Authorization::GetEffectiveRightsFromAclW(acl_ptr, trustee_ptr, &mut access_mask);
if err_code == winerror::ERROR_SUCCESS {
if err_code.is_ok() {
Ok(access_mask)
} else {
Err(io::Error::from_raw_os_error(err_code as i32))
Err(io::Error::from_raw_os_error(err_code.0 as i32))
}
}
@ -219,10 +223,10 @@ unsafe fn get_acl_access_mask(
/// Note: winapi's TRUSTEE_W looks different from the one in the MS docs because
/// of some unusual pre-processor macros in the original .h file. The winapi
/// version is correct (MS's doc generator messed up)
unsafe fn trustee_from_sid(sid_ptr: *mut c_void) -> TRUSTEE_W {
let mut trustee: TRUSTEE_W = std::mem::zeroed();
unsafe fn trustee_from_sid<P: Into<PSID>>(sid_ptr: P) -> TRUSTEE_W {
let mut trustee = TRUSTEE_W::default();
winapi::um::aclapi::BuildTrusteeWithSidW(&mut trustee, sid_ptr);
Security::Authorization::BuildTrusteeWithSidW(&mut trustee, sid_ptr);
trustee
}
@ -233,7 +237,7 @@ unsafe fn trustee_from_sid(sid_ptr: *mut c_void) -> TRUSTEE_W {
/// function execution
///
/// Returns null-terminated Vec's, one for the name and one for the domain.
unsafe fn lookup_account_sid(sid: *mut c_void) -> Result<(Vec<u16>, Vec<u16>), std::io::Error> {
unsafe fn lookup_account_sid(sid: PSID) -> Result<(Vec<u16>, Vec<u16>), std::io::Error> {
let mut name_size: u32 = BUF_SIZE;
let mut domain_size: u32 = BUF_SIZE;
@ -244,22 +248,22 @@ unsafe fn lookup_account_sid(sid: *mut c_void) -> Result<(Vec<u16>, Vec<u16>), s
let old_name_size = name_size;
let old_domain_size = domain_size;
let mut sid_name_use = 0;
let mut sid_name_use = MaybeUninit::uninit();
// Assumptions:
// - sid is a valid pointer to a SID data structure
// - name_size and domain_size accurately reflect the sizes
let result = winapi::um::winbase::LookupAccountSidW(
null_mut(),
let result = Security::LookupAccountSidW(
None,
sid,
name.as_mut_ptr(),
windows::core::PWSTR(name.as_mut_ptr()),
&mut name_size,
domain.as_mut_ptr(),
windows::core::PWSTR(domain.as_mut_ptr()),
&mut domain_size,
&mut sid_name_use,
sid_name_use.as_mut_ptr(),
);
if result != 0 {
if result.ok().is_ok() {
// Success!
return Ok((name, domain));
} else if name_size != old_name_size || domain_size != old_domain_size {
@ -271,7 +275,7 @@ unsafe fn lookup_account_sid(sid: *mut c_void) -> Result<(Vec<u16>, Vec<u16>), s
// Possibly foreign item originating from another machine
// TODO: Calculate permissions since it has to be possible if Explorer knows.
return Err(io::Error::from_raw_os_error(
winapi::um::errhandlingapi::GetLastError() as i32,
windows::Win32::Foundation::GetLastError().0 as i32,
));
}
}