Skip to content

Commit

Permalink
rework lookup_account_name to use LocalBox<Sid>
Browse files Browse the repository at this point in the history
  • Loading branch information
Guiguiprim committed Jun 7, 2023
1 parent 0953044 commit 1a63b6a
Showing 1 changed file with 59 additions and 81 deletions.
140 changes: 59 additions & 81 deletions src/wrappers/lookup_account_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,9 @@ use windows_sys::Win32::Security::{LookupAccountNameW, SID_NAME_USE};
use crate::{
constants::SidNameUse,
utilities::{buf_from_os, os_from_buf},
Sid,
LocalBox, Sid,
};

// Initial buffer size to use
// If this isn't big enough, we'll try again
const BUFFER_SIZE: usize = 256;

// If we have to retry more than this many times, panic
const MAX_RETRIES: usize = 5;

/// Wraps [`LookupAccountNameW`](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-lookupaccountnamew)
///
/// Returns SID, referenced domain name, and use in that order.
Expand All @@ -42,85 +35,70 @@ const MAX_RETRIES: usize = 5;
pub fn LookupAccountName(
system_name: Option<impl AsRef<OsStr>>,
account_name: impl AsRef<OsStr>,
) -> io::Result<(Box<Sid>, OsString, SidNameUse)> {
// Buffers to hold the SID itself, the DOM name, and the SID name use
let mut sid_buf: Vec<u8> = vec![0; BUFFER_SIZE];
let mut ref_dom_name_buf: Vec<u16> = vec![0; BUFFER_SIZE];
let mut sid_name_use: SID_NAME_USE = 0;

) -> io::Result<(LocalBox<Sid>, OsString, SidNameUse)> {
// Convert the system name and account name into buffers
let system_name = system_name.map(|s| buf_from_os(s.as_ref()));
let account_name = buf_from_os(account_name.as_ref());

let mut retry_counter = 0;

loop {
// Increment the retry counter
retry_counter += 1;

// If the retry counter passes its threshold, we panic
assert!(
retry_counter <= MAX_RETRIES,
"LookupAccountName retried too many times"
);

// Get the current length
let mut sid_len: u32 = sid_buf.len() as u32;
let mut ref_dom_name_len: u32 = ref_dom_name_buf.len() as u32;

// Convert the system name to a pointer, defaulting to null
let system_name_ptr = match system_name {
Some(ref b) => b.as_ptr(),
None => null(),
};

// Save the original values
// If the call fails
let orig_sid_len = sid_len;
let orig_ref_dom_name_len = ref_dom_name_len;
// Convert the system name to a pointer, defaulting to null
let system_name_ptr = match system_name {
Some(ref b) => b.as_ptr(),
None => null(),
};
let mut sid_len: u32 = 0;
let mut ref_dom_name_len: u32 = 0;
let mut sid_name_use: SID_NAME_USE = 0;

let result = unsafe {
LookupAccountNameW(
system_name_ptr,
account_name.as_ptr(),
sid_buf.as_mut_ptr() as *mut _,
&mut sid_len,
ref_dom_name_buf.as_mut_ptr(),
&mut ref_dom_name_len,
&mut sid_name_use,
unsafe {
LookupAccountNameW(
system_name_ptr,
account_name.as_ptr(),
std::ptr::null_mut(),
&mut sid_len,
std::ptr::null_mut(),
&mut ref_dom_name_len,
&mut sid_name_use,
)
};

let (sid, mut ref_dom_name_buf) = if sid_len != 0 && ref_dom_name_len != 0 {
(
unsafe { LocalBox::<Sid>::try_allocate(true, sid_len as usize)? },
vec![0u16; ref_dom_name_len as usize],
)
} else {
return Err(io::Error::last_os_error());
};

let result = unsafe {
LookupAccountNameW(
system_name_ptr,
account_name.as_ptr(),
sid.as_ptr() as *mut _,
&mut sid_len,
ref_dom_name_buf.as_mut_ptr(),
&mut ref_dom_name_len,
&mut sid_name_use,
)
};

if result != 0 {
// Success! Return the appropriate values, converting as necessary

// Convert the referenced domain name into an OsString
let ref_dom_name = os_from_buf(&ref_dom_name_buf);

// Figure out SidNameUse
let sid_name_use = SidNameUse::from_raw(sid_name_use).unwrap_or_else(|| {
panic!(
"LookupAccountNameW returned unrecognized SidNameUse variant {:?}",
sid_name_use
)
};

if result != 0 {
// Success! Return the appropriate values, converting as necessary

// Resize the SID buffer based on the SID length and convert to a Box
sid_buf.truncate(sid_len as usize);
let sid_box = sid_buf.into_boxed_slice();
let sid = unsafe { Box::from_raw(Box::into_raw(sid_box) as *mut Sid) };

// Convert the referenced domain name into an OsString
let ref_dom_name = os_from_buf(&ref_dom_name_buf);

// Figure out SidNameUse
let sid_name_use = SidNameUse::from_raw(sid_name_use).unwrap_or_else(|| {
panic!(
"LookupAccountNameW returned unrecognized SidNameUse variant {:?}",
sid_name_use
)
});

break Ok((sid, ref_dom_name, sid_name_use));
} else if sid_len != orig_sid_len || ref_dom_name_len != orig_ref_dom_name_len {
// Failure! They indicated a reallocation requirement
});

// Resize both the SID buffer and the referenced domain name buffer based
// on the indicated correct sizes
sid_buf.resize(sid_len as usize, 0);
ref_dom_name_buf.resize(ref_dom_name_len as usize, 0);
} else {
// Failure! We're not recovering
break Err(io::Error::last_os_error());
}
Ok((sid, ref_dom_name, sid_name_use))
} else {
// Failure! We're not recovering
Err(io::Error::last_os_error())
}
}

0 comments on commit 1a63b6a

Please sign in to comment.