use crate::winapi_;
use super::utf16_from_string;
use super::utf16_to_string;
pub const NAME_SAM_COMPATIBLE: u32 = 2;
pub const NAME_DISPLAY: u32 = 3;
extern "system" {
pub fn TranslateNameW(
lpAccountName: winapi_::LPCWSTR,
AccountNameFormat: u32,
DesiredNameFormat: u32,
lpTranslatedName: winapi_::LPWSTR,
nSize: *mut u32,
) -> winapi_::BOOLEAN;
}
pub fn translate_account_name(
username: &str,
from_format: u32,
to_format: u32,
) -> std::io::Result<String> {
let u = utf16_from_string(username);
let mut n = 50_u32;
let mut b = vec![0_u16; n as usize];
loop {
let e =
unsafe { TranslateNameW(u.as_ptr(), from_format, to_format, b.as_mut_ptr(), &mut n) };
if e == 0 {
let last_err = std::io::Error::last_os_error();
if last_err.raw_os_error().unwrap() == winapi_::ERROR_INSUFFICIENT_BUFFER as i32 {
b.resize(n as usize, 0);
continue;
}
return Err(last_err);
}
return Ok(utf16_to_string(&b[..n as usize]));
}
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn sid_to_string(sid: winapi_::PSID) -> std::io::Result<String> {
let mut raw_string: winapi_::LPWSTR = std::ptr::null_mut();
let res = unsafe { winapi_::ConvertSidToStringSidW(sid, &mut raw_string) };
if res == 0 {
return Err(std::io::Error::last_os_error());
}
let s = super::utf16_ptr_to_string(raw_string);
unsafe { winapi_::LocalFree(raw_string as *mut winapi_::c_void) };
Ok(s)
}
#[derive(Debug)]
pub struct AccontLookupResult {
pub account: String,
pub domain: String,
pub acc_type: u32,
}
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn lookup_account(sid: winapi_::PSID, system: &str) -> std::io::Result<AccontLookupResult> {
let system_wide_str: Vec<u16>;
let mut system_wide_str_ptr = std::ptr::null::<u16>();
if !system.is_empty() {
system_wide_str = super::utf16_from_string(system);
system_wide_str_ptr = system_wide_str.as_ptr();
}
let mut n = 50_u32;
let mut dn = 50_u32;
let mut b = vec![0_u16; n as usize];
let mut db = vec![0_u16; dn as usize];
let mut acc_type = 0;
loop {
let ret = unsafe {
winapi_::LookupAccountSidW(
system_wide_str_ptr,
sid,
b.as_mut_ptr(),
&mut n,
db.as_mut_ptr(),
&mut dn,
&mut acc_type,
)
};
if ret == 0 {
let last_err = std::io::Error::last_os_error();
if last_err.raw_os_error().unwrap() == winapi_::ERROR_INSUFFICIENT_BUFFER as i32 {
if n as usize > b.len() || dn as usize > db.len() {
b.resize(n as usize, 0);
db.resize(dn as usize, 0);
continue;
} else {
return Err(last_err);
}
}
return Err(last_err);
}
return Ok(AccontLookupResult {
account: super::utf16_to_string(&b),
domain: super::utf16_to_string(&db),
acc_type,
});
}
}
#[derive(Debug)]
pub struct Tokenuser {
raw_data: Vec<u8>,
}
impl Tokenuser {
fn get(&self) -> *const winapi_::TOKEN_USER {
self.raw_data.as_ptr() as winapi_::PTOKEN_USER
}
pub fn get_sid(&self) -> winapi_::PSID {
let p = self.get();
unsafe { (*p).User.Sid }
}
}
#[derive(Debug)]
pub struct Tokenprimarygroup {
raw_data: Vec<u8>,
}
impl Tokenprimarygroup {
fn get(&self) -> *const winapi_::TOKEN_PRIMARY_GROUP {
self.raw_data.as_ptr() as winapi_::PTOKEN_PRIMARY_GROUP
}
pub fn get_sid(&self) -> winapi_::PSID {
let p = self.get();
unsafe { (*p).PrimaryGroup }
}
}
#[derive(Debug)]
pub struct Token {
pub h: winapi_::HANDLE,
}
impl Drop for Token {
fn drop(&mut self) {
_ = Token::close(self);
}
}
pub fn open_current_process_token() -> std::io::Result<Token> {
unsafe {
let p = winapi_::GetCurrentProcess();
let mut token: Token = Token {
h: std::ptr::null_mut(),
};
let result = winapi_::OpenProcessToken(p, winapi_::TOKEN_QUERY, &mut token.h);
get_error(result)?;
Ok(token)
}
}
impl Token {
pub fn close(&mut self) -> std::io::Result<()> {
unsafe { get_error(winapi_::CloseHandle(self.h)) }
}
fn get_info(&self, class: u32, init_size: usize) -> std::io::Result<Vec<u8>> {
let mut n = init_size as u32;
let mut b = vec![0_u8; n as usize];
loop {
let e = unsafe {
winapi_::GetTokenInformation(
self.h,
class,
b.as_mut_ptr() as winapi_::LPVOID,
n,
&mut n,
)
};
if e == 0 {
let last_err = std::io::Error::last_os_error();
if last_err.raw_os_error().unwrap() == winapi_::ERROR_INSUFFICIENT_BUFFER as i32 {
b.resize(n as usize, 0);
continue;
}
return Err(last_err);
}
return Ok(b);
}
}
pub fn get_token_user(&self) -> std::io::Result<Tokenuser> {
Ok(Tokenuser {
raw_data: self.get_info(winapi_::TokenUser, 50)?,
})
}
pub fn get_token_primary_group(&self) -> std::io::Result<Tokenprimarygroup> {
Ok(Tokenprimarygroup {
raw_data: self.get_info(winapi_::TokenPrimaryGroup, 50)?,
})
}
pub fn get_user_profile_directory(&self) -> std::io::Result<String> {
let mut n = 100_u32;
let mut b = vec![0_u16; n as usize];
loop {
let e = unsafe { winapi_::GetUserProfileDirectoryW(self.h, b.as_mut_ptr(), &mut n) };
if e == 0 {
let last_err = std::io::Error::last_os_error();
if last_err.raw_os_error().unwrap() == winapi_::ERROR_INSUFFICIENT_BUFFER as i32 {
b.resize(n as usize, 0);
continue;
}
return Err(last_err);
}
return Ok(super::utf16_to_string(&b));
}
}
}
pub fn get_error(res: winapi_::BOOL) -> std::io::Result<()> {
if res == 0 {
Err(std::io::Error::last_os_error())
} else {
Ok(())
}
}
#[allow(clippy::missing_safety_doc)]
pub unsafe fn close_handle(h: winapi_::HANDLE) -> std::io::Result<()> {
unsafe { get_error(winapi_::CloseHandle(h)) }
}