diff --git a/Cargo.lock b/Cargo.lock index 872812e..8b3f808 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 3e4421a..996c7d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/src/main.rs b/src/main.rs index 78bdac9..a0f54f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ extern crate yaml_rust; extern crate users; #[cfg(windows)] -extern crate winapi; +extern crate windows; mod app; mod color; diff --git a/src/meta/windows_utils.rs b/src/meta/windows_utils.rs index 456f850..7fbf07e 100644 --- a/src/meta/windows_utils.rs +++ b/src/meta/windows_utils.rs @@ -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 { 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>(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, Vec), std::io::Error> { +unsafe fn lookup_account_sid(sid: PSID) -> Result<(Vec, Vec), 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, Vec), 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, Vec), 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, )); } }