use std::fs::File;
use std::io;
use std::path::Path;
#[cfg(windows)]
use winapi::um::winnt::{FILE_GENERIC_READ, FILE_GENERIC_WRITE, STANDARD_RIGHTS_ALL};
#[cfg(windows)]
const OWNER_SID_STR: &str = "S-1-3-4";
#[cfg(windows)]
const OWNER_ACL_ENTRY_FLAGS: u8 = 0;
#[cfg(windows)]
const OWNER_ACL_ENTRY_MASK: u32 = FILE_GENERIC_READ | FILE_GENERIC_WRITE | STANDARD_RIGHTS_ALL;
#[cfg(unix)]
pub fn restrict_file_permissions<P: AsRef<Path>>(_path: P, file: File) -> io::Result<File> {
use std::os::unix::fs::PermissionsExt;
let mut perm = file.metadata()?.permissions();
perm.set_mode(0o600);
file.set_permissions(perm)?;
Ok(file)
}
#[cfg(windows)]
pub fn restrict_file_permissions<P: AsRef<Path>>(path: P, file: File) -> io::Result<File> {
use winapi::um::winnt::PSID;
use windows_acl::acl::{AceType, ACL};
use windows_acl::helper::sid_to_string;
let path_str = path.as_ref().to_str().ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
"Unable to open file path.".to_string(),
)
})?;
let mut acl = ACL::from_file_path(path_str, false).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Unable to retrieve ACL: {:?}", e),
)
})?;
let owner_sid = windows_acl::helper::string_to_sid(OWNER_SID_STR).map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Unable to convert SID: {:?}", e),
)
})?;
let entries = acl.all().map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!("Unable to enumerate ACL entries: {:?}", e),
)
})?;
acl.add_entry(
owner_sid.as_ptr() as PSID,
AceType::AccessAllow,
OWNER_ACL_ENTRY_FLAGS,
OWNER_ACL_ENTRY_MASK,
)
.map_err(|e| {
io::Error::new(
io::ErrorKind::Other,
format!(
"Failed to add ACL entry for SID {} error={}",
OWNER_SID_STR, e
),
)
})?;
for entry in &entries {
if let Some(ref entry_sid) = entry.sid {
let entry_sid_str = sid_to_string(entry_sid.as_ptr() as PSID)
.unwrap_or_else(|_| "BadFormat".to_string());
if entry_sid_str != OWNER_SID_STR {
acl.remove(entry_sid.as_ptr() as PSID, Some(AceType::AccessAllow), None)
.map_err(|_| {
io::Error::new(
io::ErrorKind::Other,
format!("Failed to remove ACL entry for SID {}", entry_sid_str),
)
})?;
}
}
}
Ok(file)
}
#[cfg(not(any(unix, windows)))]
pub fn restrict_file_permissions<P: AsRef<Path>>(_path: P, _file: File) -> io::Result<File> {
Err(io::Error::new(
io::ErrorKind::Other,
"`restrict_permissions` feature is only available on Unix or Windows",
))
}