use std::ffi::OsString;
use std::fmt;
use std::io;
use std::mem::MaybeUninit;
use std::ptr;
use std::slice;
pub use windows_sys::Win32::Foundation::PSID;
use windows_sys::Win32::Foundation::{GetLastError, LocalFree, ERROR_NONE_MAPPED, HLOCAL};
use windows_sys::Win32::Security::Authorization::ConvertSidToStringSidW;
use windows_sys::Win32::Security::{
CopySid, CreateWellKnownSid, EqualSid, GetLengthSid, GetSidLengthRequired, IsValidSid,
LookupAccountSidW, SidTypeUnknown, WinWorldSid,
};
use super::utils;
use crate::Error;
pub fn copy_sid(psid: PSID) -> Result<Vec<u8>, io::Error> {
let sid_length = unsafe { GetLengthSid(psid) };
let mut buf: Vec<u8> = vec![0; sid_length as usize];
let return_code = unsafe { CopySid(sid_length, buf.as_mut_ptr() as PSID, psid) };
if return_code != 0 {
Ok(buf)
} else {
Err(io::Error::last_os_error())
}
}
pub fn lookup_account_sid(psid: PSID) -> Result<OsString, Error> {
let mut wide_name_length: u32 = 32;
let mut wide_domain_length: u32 = 32;
let mut wide_name_buf: [u16; 32] = [0; 32];
let mut wide_domain_buf: [u16; 32] = [0; 32];
let mut sid_name_use = SidTypeUnknown;
let return_code = unsafe {
LookupAccountSidW(
ptr::null(),
psid,
wide_name_buf.as_mut_ptr(),
&mut wide_name_length,
wide_domain_buf.as_mut_ptr(),
&mut wide_domain_length,
&mut sid_name_use,
)
};
if return_code != 0 {
Ok(utils::accountname_from_wide_domain_and_name(
&wide_domain_buf,
&wide_name_buf,
))
}
else if unsafe { GetLastError() } == ERROR_NONE_MAPPED {
Err(Error::NoRecord)
} else {
let mut wide_name = vec![0; wide_name_length as usize];
let mut wide_domain = vec![0; wide_domain_length as usize];
let return_code = unsafe {
LookupAccountSidW(
ptr::null(),
psid,
wide_name.as_mut_ptr(),
&mut wide_name_length,
wide_domain.as_mut_ptr(),
&mut wide_domain_length,
&mut sid_name_use,
)
};
if return_code != 0 {
Ok(utils::accountname_from_wide_domain_and_name(
&wide_domain_buf,
&wide_name_buf,
))
} else {
Err(Error::NoRecord)
}
}
}
pub(crate) fn fmt_sid(psid: PSID, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match convert_sid_to_string_sid(psid) {
Ok(string_sid) => write!(f, "{}", string_sid),
Err(_) => Err(fmt::Error),
}
}
pub fn convert_sid_to_string_sid(psid: PSID) -> Result<String, io::Error> {
let mut wide_cstring_sid = MaybeUninit::<*mut u16>::uninit();
let return_code = unsafe { ConvertSidToStringSidW(psid, wide_cstring_sid.as_mut_ptr()) };
if return_code != 0 {
let wide_cstring_sid = unsafe { wide_cstring_sid.assume_init() };
let wide_cstring_sid_len = unsafe { libc::wcslen(wide_cstring_sid) };
let wide_cstring_sid_slice =
unsafe { slice::from_raw_parts(wide_cstring_sid, wide_cstring_sid_len) };
let string_sid = String::from_utf16_lossy(wide_cstring_sid_slice);
unsafe { LocalFree(wide_cstring_sid as HLOCAL) };
Ok(string_sid)
} else {
Err(io::Error::last_os_error())
}
}
pub fn equal_sid(psid_1: PSID, psid_2: PSID) -> bool {
unsafe { EqualSid(psid_1, psid_2) != 0 }
}
pub fn is_invalid_sid(psid: PSID) -> bool {
psid.is_null() || (unsafe { IsValidSid(psid) } == 0)
}
pub(crate) fn create_world_sid() -> Result<Vec<u8>, io::Error> {
let mut world_sid_len = unsafe { GetSidLengthRequired(1) };
let mut buf: Vec<u8> = vec![0; world_sid_len as usize];
let return_code = unsafe {
CreateWellKnownSid(
WinWorldSid,
ptr::null_mut(),
buf.as_mut_ptr() as PSID,
&mut world_sid_len,
)
};
if return_code != 0 {
Ok(buf)
} else {
Err(io::Error::last_os_error())
}
}