#![allow(
unsafe_code,
reason = "the Win32 security API is C; each call is bracketed and its result checked"
)]
use std::io;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use windows_sys::Win32::Foundation::{CloseHandle, ERROR_SUCCESS, HANDLE, LocalFree};
use windows_sys::Win32::Security::Authorization::{
EXPLICIT_ACCESS_W, NO_MULTIPLE_TRUSTEE, SE_FILE_OBJECT, SET_ACCESS, SetEntriesInAclW,
SetNamedSecurityInfoW, TRUSTEE_IS_SID, TRUSTEE_IS_USER, TRUSTEE_W,
};
use windows_sys::Win32::Security::{
ACL, DACL_SECURITY_INFORMATION, GetTokenInformation, PROTECTED_DACL_SECURITY_INFORMATION,
TOKEN_QUERY, TOKEN_USER, TokenUser,
};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
const NO_INHERITANCE: u32 = 0;
const GENERIC_ALL: u32 = 0x1000_0000;
struct Handle(HANDLE);
impl Drop for Handle {
fn drop(&mut self) {
unsafe { CloseHandle(self.0) };
}
}
struct LocalAcl(*mut ACL);
impl Drop for LocalAcl {
fn drop(&mut self) {
unsafe { LocalFree(self.0.cast()) };
}
}
fn win32(code: u32) -> io::Error {
io::Error::from_raw_os_error(code as i32)
}
pub(crate) fn restrict_to_current_user(path: &Path) -> io::Result<()> {
let mut token: HANDLE = std::ptr::null_mut();
if unsafe { OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token) } == 0 {
return Err(io::Error::last_os_error());
}
let token = Handle(token);
let mut len = 0u32;
unsafe { GetTokenInformation(token.0, TokenUser, std::ptr::null_mut(), 0, &mut len) };
if len == 0 {
return Err(io::Error::last_os_error());
}
let mut buf = vec![0u64; (len as usize).div_ceil(8)];
if unsafe { GetTokenInformation(token.0, TokenUser, buf.as_mut_ptr().cast(), len, &mut len) }
== 0
{
return Err(io::Error::last_os_error());
}
let sid = unsafe { (*buf.as_ptr().cast::<TOKEN_USER>()).User.Sid };
let entry = EXPLICIT_ACCESS_W {
grfAccessPermissions: GENERIC_ALL,
grfAccessMode: SET_ACCESS,
grfInheritance: NO_INHERITANCE,
Trustee: TRUSTEE_W {
pMultipleTrustee: std::ptr::null_mut(),
MultipleTrusteeOperation: NO_MULTIPLE_TRUSTEE,
TrusteeForm: TRUSTEE_IS_SID,
TrusteeType: TRUSTEE_IS_USER,
ptstrName: sid.cast(),
},
};
let mut acl: *mut ACL = std::ptr::null_mut();
let code = unsafe { SetEntriesInAclW(1, &entry, std::ptr::null(), &mut acl) };
if code != ERROR_SUCCESS {
return Err(win32(code));
}
let acl = LocalAcl(acl);
let wide: Vec<u16> = path.as_os_str().encode_wide().chain([0]).collect();
let code = unsafe {
SetNamedSecurityInfoW(
wide.as_ptr(),
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
std::ptr::null_mut(),
std::ptr::null_mut(),
acl.0,
std::ptr::null(),
)
};
if code != ERROR_SUCCESS {
return Err(win32(code));
}
Ok(())
}