use windows::{
Win32::{
Foundation::{HLOCAL, LocalFree},
Security::{
Authorization::{ConvertSidToStringSidW, ConvertStringSidToSidW},
EqualSid, PSID,
},
},
core::{PCWSTR, PWSTR},
};
use super::win32;
use crate::error::ElevateError;
pub struct Sid(PSID);
impl Drop for Sid {
fn drop(&mut self) {
if !self.0.is_invalid() {
unsafe {
let _ = LocalFree(HLOCAL(self.0.0));
}
}
}
}
impl Sid {
pub fn parse(s: PCWSTR) -> Result<Self, ElevateError> {
let mut psid = PSID::default();
win32!(ConvertStringSidToSidW(s, &raw mut psid))?;
Ok(Self(psid))
}
pub const fn as_raw(&self) -> PSID {
self.0
}
pub fn equal(a: PSID, b: PSID) -> bool {
unsafe { EqualSid(a, b).is_ok() }
}
pub fn string_from_raw(psid: PSID) -> Result<String, ElevateError> {
let mut pwstr = PWSTR::null();
win32!(ConvertSidToStringSidW(psid, &raw mut pwstr))?;
let res = unsafe { pwstr.to_string() }.map_err(|_| ElevateError::InvalidTokenBuffer);
unsafe {
let _ = LocalFree(HLOCAL(pwstr.0.cast()));
}
res
}
}
#[cfg(test)]
mod tests {
use super::*;
use windows::core::w;
#[test]
fn test_sid_parse_and_string_conversion() {
let raw_str = w!("S-1-5-18");
let sid = Sid::parse(raw_str).expect("Failed to parse well-known SYSTEM SID");
let formatted = Sid::string_from_raw(sid.as_raw()).expect("Failed to stringify SID");
assert_eq!(formatted, "S-1-5-18");
}
}