diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:35 +0000 |
commit | d1b2d29528b7794b41e66fc2136e395a02f8529b (patch) | |
tree | a4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/sysinfo/src/windows/users.rs | |
parent | Releasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/sysinfo/src/windows/users.rs')
-rw-r--r-- | vendor/sysinfo/src/windows/users.rs | 204 |
1 files changed, 127 insertions, 77 deletions
diff --git a/vendor/sysinfo/src/windows/users.rs b/vendor/sysinfo/src/windows/users.rs index 2fef05c3f..fa979e731 100644 --- a/vendor/sysinfo/src/windows/users.rs +++ b/vendor/sysinfo/src/windows/users.rs @@ -3,31 +3,88 @@ use crate::sys::utils::to_str; use crate::{ common::{Gid, Uid}, + windows::sid::Sid, User, }; use std::ptr::null_mut; use winapi::shared::lmcons::{MAX_PREFERRED_LENGTH, NET_API_STATUS}; -use winapi::shared::minwindef::DWORD; +use winapi::shared::minwindef::{DWORD, LPBYTE}; use winapi::shared::ntstatus::STATUS_SUCCESS; use winapi::shared::winerror::ERROR_MORE_DATA; -use winapi::um::lmaccess::{NetUserEnum, NetUserGetLocalGroups}; use winapi::um::lmaccess::{ - FILTER_NORMAL_ACCOUNT, LG_INCLUDE_INDIRECT, LPLOCALGROUP_USERS_INFO_0, USER_INFO_0, + NetUserEnum, NetUserGetInfo, NetUserGetLocalGroups, LOCALGROUP_USERS_INFO_0, USER_INFO_23, }; +use winapi::um::lmaccess::{FILTER_NORMAL_ACCOUNT, LG_INCLUDE_INDIRECT, USER_INFO_0}; use winapi::um::lmapibuf::NetApiBufferFree; use winapi::um::ntlsa::{ LsaEnumerateLogonSessions, LsaFreeReturnBuffer, LsaGetLogonSessionData, - PSECURITY_LOGON_SESSION_DATA, + SECURITY_LOGON_SESSION_DATA, }; -use winapi::um::winnt::{LPWSTR, PLUID}; +use winapi::um::winnt::{LPWSTR, LUID}; -// FIXME: once this is mreged in winapi, it can be removed. +// FIXME: Can be removed once merged in winapi. #[allow(non_upper_case_globals)] const NERR_Success: NET_API_STATUS = 0; +struct NetApiBuffer<T>(*mut T); + +impl<T> Drop for NetApiBuffer<T> { + fn drop(&mut self) { + unsafe { + if !self.0.is_null() { + NetApiBufferFree(self.0 as *mut _); + } + } + } +} + +impl<T> Default for NetApiBuffer<T> { + fn default() -> Self { + Self(null_mut()) + } +} + +impl<T> NetApiBuffer<T> { + pub fn inner_mut(&mut self) -> &mut *mut T { + assert!(self.0.is_null()); + &mut self.0 + } + + pub unsafe fn inner_mut_as_bytes(&mut self) -> &mut LPBYTE { + // https://doc.rust-lang.org/std/mem/fn.transmute.html + // Turning an &mut T into an &mut U: + &mut *(self.inner_mut() as *mut *mut T as *mut LPBYTE) + } +} + +struct LsaBuffer<T>(*mut T); + +impl<T> Drop for LsaBuffer<T> { + fn drop(&mut self) { + unsafe { + if !self.0.is_null() { + LsaFreeReturnBuffer(self.0 as *mut _); + } + } + } +} + +impl<T> Default for LsaBuffer<T> { + fn default() -> Self { + Self(null_mut()) + } +} + +impl<T> LsaBuffer<T> { + pub fn inner_mut(&mut self) -> &mut *mut T { + assert!(self.0.is_null()); + &mut self.0 + } +} + unsafe fn get_groups_for_user(username: LPWSTR) -> Vec<String> { - let mut buf: LPLOCALGROUP_USERS_INFO_0 = null_mut(); + let mut buf: NetApiBuffer<LOCALGROUP_USERS_INFO_0> = Default::default(); let mut nb_entries = 0; let mut total_entries = 0; let mut groups; @@ -37,7 +94,7 @@ unsafe fn get_groups_for_user(username: LPWSTR) -> Vec<String> { username, 0, LG_INCLUDE_INDIRECT, - &mut buf as *mut _ as _, + buf.inner_mut_as_bytes(), MAX_PREFERRED_LENGTH, &mut nb_entries, &mut total_entries, @@ -45,83 +102,62 @@ unsafe fn get_groups_for_user(username: LPWSTR) -> Vec<String> { if status == NERR_Success { groups = Vec::with_capacity(nb_entries as _); - - if !buf.is_null() { - for i in 0..nb_entries { - let tmp = buf.offset(i as _); - if tmp.is_null() { - break; - } - groups.push(to_str((*tmp).lgrui0_name)); - } + if !buf.0.is_null() { + let entries = std::slice::from_raw_parts(buf.0, nb_entries as _); + groups.extend(entries.iter().map(|entry| to_str(entry.lgrui0_name))); } } else { groups = Vec::new(); sysinfo_debug!("NetUserGetLocalGroups failed with ret code {}", status); } - if !buf.is_null() { - NetApiBufferFree(buf as *mut _); - } groups } -// FIXME: For now, the Uid is the user name, which is quite bad. Normally, there is `PSID` for -// that. But when getting the `PSID` from the processes, it doesn't match the ones we have for -// the users (`EqualSid`). Anyway, until I have time and motivation to fix this. It'll remain -// like that... pub unsafe fn get_users() -> Vec<User> { let mut users = Vec::new(); - let mut buffer: *mut USER_INFO_0 = null_mut(); - let mut nb_read = 0; - let mut total = 0; - let mut resume_handle: DWORD = 0; + let mut resume_handle: DWORD = 0; loop { + let mut buffer: NetApiBuffer<USER_INFO_0> = Default::default(); + let mut nb_read = 0; + let mut total = 0; let status = NetUserEnum( null_mut(), 0, FILTER_NORMAL_ACCOUNT, - &mut buffer as *mut _ as *mut _, + buffer.inner_mut_as_bytes(), MAX_PREFERRED_LENGTH, &mut nb_read, &mut total, - &mut resume_handle as *mut _ as *mut _, + &mut resume_handle, ); if status == NERR_Success || status == ERROR_MORE_DATA { - let entries: &[USER_INFO_0] = std::slice::from_raw_parts(buffer, nb_read as _); + let entries = std::slice::from_raw_parts(buffer.0, nb_read as _); for entry in entries { if entry.usri0_name.is_null() { continue; } - // let mut user: *mut USER_INFO_23 = null_mut(); - - // if NetUserGetInfo( - // null_mut(), - // entry.usri0_name, - // 23, - // &mut user as *mut _ as *mut _, - // ) == NERR_Success - // { - // let groups = get_groups_for_user((*user).usri23_name); - // users.push(User { - // uid: Uid(name.clone().into_boxed_str()), - // gid: Gid(0), - // name: to_str((*user).usri23_name), - // groups, - // }); - // } - // if !user.is_null() { - // NetApiBufferFree(user as *mut _); - // } - let groups = get_groups_for_user(entry.usri0_name); - let name = to_str(entry.usri0_name); - users.push(User { - uid: Uid(name.clone().into_boxed_str()), - gid: Gid(0), - name, - groups, - }); + + let mut user: NetApiBuffer<USER_INFO_23> = Default::default(); + if NetUserGetInfo(null_mut(), entry.usri0_name, 23, user.inner_mut_as_bytes()) + == NERR_Success + { + if let Some(sid) = Sid::from_psid((*user.0).usri23_user_sid) { + // Get the account name from the SID (because it's usually + // a better name), but fall back to the name we were given + // if this fails. + let name = sid + .account_name() + .unwrap_or_else(|| to_str(entry.usri0_name)); + users.push(User { + uid: Uid(sid), + gid: Gid(0), + name, + groups: get_groups_for_user(entry.usri0_name), + }); + } + } } } else { sysinfo_debug!( @@ -135,10 +171,6 @@ pub unsafe fn get_users() -> Vec<User> { } ); } - if !buffer.is_null() { - NetApiBufferFree(buffer as *mut _); - buffer = null_mut(); - } if status != ERROR_MORE_DATA { break; } @@ -146,34 +178,52 @@ pub unsafe fn get_users() -> Vec<User> { // First part done. Second part now! let mut nb_sessions = 0; - let mut uids: PLUID = null_mut(); - if LsaEnumerateLogonSessions(&mut nb_sessions, &mut uids) != STATUS_SUCCESS { + let mut uids: LsaBuffer<LUID> = Default::default(); + if LsaEnumerateLogonSessions(&mut nb_sessions, uids.inner_mut()) != STATUS_SUCCESS { sysinfo_debug!("LsaEnumerateLogonSessions failed"); } else { - for offset in 0..nb_sessions { - let entry = uids.add(offset as _); - let mut data: PSECURITY_LOGON_SESSION_DATA = null_mut(); - - if LsaGetLogonSessionData(entry, &mut data) == STATUS_SUCCESS && !data.is_null() { - let data = *data; + let entries = std::slice::from_raw_parts_mut(uids.0, nb_sessions as _); + for entry in entries { + let mut data: LsaBuffer<SECURITY_LOGON_SESSION_DATA> = Default::default(); + if LsaGetLogonSessionData(entry, data.inner_mut()) == STATUS_SUCCESS + && !data.0.is_null() + { + let data = *data.0; if data.LogonType == winapi::um::ntlsa::Network { continue; } - let name = to_str(data.UserName.Buffer); - if users.iter().any(|u| u.name == name) { + + let sid = match Sid::from_psid(data.Sid) { + Some(sid) => sid, + None => continue, + }; + + if users.iter().any(|u| u.uid.0 == sid) { continue; } + + // Get the account name from the SID (because it's usually + // a better name), but fall back to the name we were given + // if this fails. + let name = sid.account_name().unwrap_or_else(|| { + String::from_utf16(std::slice::from_raw_parts( + data.UserName.Buffer, + data.UserName.Length as usize / std::mem::size_of::<u16>(), + )) + .unwrap_or_else(|_err| { + sysinfo_debug!("Failed to convert from UTF-16 string: {}", _err); + String::new() + }) + }); + users.push(User { - uid: Uid(name.clone().into_boxed_str()), + uid: Uid(sid), gid: Gid(0), name, // There is no local groups for a non-local user. groups: Vec::new(), }); } - if !data.is_null() { - LsaFreeReturnBuffer(data as *mut _); - } } } |