summaryrefslogtreecommitdiffstats
path: root/vendor/sysinfo/src/windows/users.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/sysinfo/src/windows/users.rs
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-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.rs204
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 _);
- }
}
}