use windows::Win32::NetworkManagement::NetManagement::{
LOCALGROUP_INFO_1, LOCALGROUP_MEMBERS_INFO_2, NetLocalGroupEnum, NetLocalGroupGetMembers,
};
use windows::{
Win32::NetworkManagement::NetManagement::{
LOCALGROUP_MEMBERS_INFO_3, NetApiBufferFree, NetLocalGroupAddMembers,
NetLocalGroupDelMembers,
},
core::{PCWSTR, PWSTR},
};
use crate::utils::net_api_result;
use crate::{error::WindowsUsersError, utils::to_wide};
pub use crate::groups::types::{Group, GroupMember};
pub mod sid;
mod types;
pub fn list_groups(server_name: Option<&str>) -> Result<Vec<Group>, WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let mut buffer = std::ptr::null_mut();
let mut entries_read = 0;
let mut total_entries = 0;
let mut resume_handle = 0;
let status = unsafe {
NetLocalGroupEnum(
server_name,
1,
&mut buffer,
u32::MAX,
&mut entries_read,
&mut total_entries,
Some(&mut resume_handle),
)
};
let _guard = scopeguard::guard(buffer, |buf| {
if !buf.is_null() {
unsafe { NetApiBufferFree(Some(buf.cast())) };
}
});
net_api_result(status)?;
if entries_read == 0 || buffer.is_null() {
return Ok(Vec::new());
}
let groups = unsafe {
std::slice::from_raw_parts(buffer as *const LOCALGROUP_INFO_1, entries_read as usize)
.iter()
.map(Group::try_from)
.collect::<Result<Vec<_>, _>>()
}?;
Ok(groups)
}
pub fn list_group_members(
server_name: Option<&str>,
group: &str,
) -> Result<Vec<GroupMember>, WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let group_w = to_wide(group);
let mut buffer = std::ptr::null_mut();
let mut entries_read = 0;
let mut total_entries = 0;
let mut resume_handle = 0;
let status = unsafe {
NetLocalGroupGetMembers(
server_name,
PCWSTR(group_w.as_ptr()),
2,
&mut buffer,
u32::MAX,
&mut entries_read,
&mut total_entries,
Some(&mut resume_handle),
)
};
let _guard = scopeguard::guard(buffer, |buf| {
if !buf.is_null() {
unsafe { NetApiBufferFree(Some(buf.cast())) };
}
});
net_api_result(status)?;
if entries_read == 0 || buffer.is_null() {
return Ok(Vec::new());
}
let members = unsafe {
std::slice::from_raw_parts(
buffer as *const LOCALGROUP_MEMBERS_INFO_2,
entries_read as usize,
)
.iter()
.map(GroupMember::try_from)
.collect::<Result<Vec<_>, _>>()
}?;
Ok(members)
}
pub fn add_user_to_group(
server_name: Option<&str>,
username: &str,
group: &str,
) -> Result<(), WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let mut user_w = to_wide(username);
let group_w = to_wide(group);
let mut member = LOCALGROUP_MEMBERS_INFO_3 {
lgrmi3_domainandname: PWSTR(user_w.as_mut_ptr()),
};
let status = unsafe {
NetLocalGroupAddMembers(
server_name,
PCWSTR(group_w.as_ptr()),
3,
&mut member as *mut LOCALGROUP_MEMBERS_INFO_3 as *const u8,
1,
)
};
net_api_result(status)
}
pub fn remove_user_from_group(
server_name: Option<&str>,
username: &str,
group: &str,
) -> Result<(), WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let mut user_w = to_wide(username);
let group_w = to_wide(group);
let mut member = LOCALGROUP_MEMBERS_INFO_3 {
lgrmi3_domainandname: PWSTR(user_w.as_mut_ptr()),
};
let status = unsafe {
NetLocalGroupDelMembers(
server_name,
PCWSTR(group_w.as_ptr()),
3,
&mut member as *mut LOCALGROUP_MEMBERS_INFO_3 as *const u8,
1,
)
};
net_api_result(status)
}