use windows::{
Win32::NetworkManagement::NetManagement::{
NetApiBufferFree, NetUserAdd, NetUserChangePassword, NetUserDel, NetUserGetInfo,
USER_INFO_4,
},
core::PCWSTR,
};
use crate::{
LogonHours, User, UserUpdate,
error::WindowsUsersError,
set_user_account_expiration, set_user_comment, set_user_country_code, set_user_flags,
set_user_full_name, set_user_home_dir_drive, set_user_home_directory, set_user_logon_hours,
set_user_name, set_user_password, set_user_primary_group, set_user_profile,
set_user_script_path, set_user_user_comment, set_user_workstations,
utils::{net_api_result, net_api_result_with_index, to_wide},
};
pub mod update_ops;
pub fn add_user(server_name: Option<&str>, user: &User) -> Result<(), WindowsUsersError> {
let server_name_p = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let mut info = user.to_user_info_4();
let mut parm_err = 0;
let status = unsafe {
NetUserAdd(
server_name_p,
4,
&mut info.user_info as *mut USER_INFO_4 as *const u8,
Some(&mut parm_err),
)
};
net_api_result_with_index(status, parm_err)?;
Ok(())
}
pub fn add_user_if_not_exists(
server_name: Option<&str>,
user: &User,
) -> Result<bool, WindowsUsersError> {
if user_exists(server_name, user.name()) {
Ok(false)
} else {
add_user(server_name, user)?;
Ok(true)
}
}
pub fn add_user_or_update(
server_name: Option<&str>,
user: &User,
) -> Result<bool, WindowsUsersError> {
if user_exists(server_name, user.name()) {
update_user(server_name, user.name(), &UserUpdate::from(user.clone()))?;
Ok(false)
} else {
add_user(server_name, user)?;
Ok(true)
}
}
pub fn delete_user(server_name: Option<&str>, username: &str) -> Result<(), WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let username_w = to_wide(username);
let status = unsafe { NetUserDel(server_name, PCWSTR(username_w.as_ptr())) };
net_api_result(status)
}
pub fn change_user_password(
server_name: Option<&str>,
username: &str,
old_password: &str,
new_password: &str,
) -> Result<(), WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let username_w = to_wide(username);
let old_pw_w = to_wide(old_password);
let new_pw_w = to_wide(new_password);
let status = unsafe {
NetUserChangePassword(
server_name,
PCWSTR(username_w.as_ptr()),
PCWSTR(old_pw_w.as_ptr()),
PCWSTR(new_pw_w.as_ptr()),
)
};
net_api_result(status)
}
pub fn update_user(
server_name: Option<&str>,
username: &str,
settings: &UserUpdate,
) -> Result<(), WindowsUsersError> {
if let Some(ref password) = settings.password {
set_user_password(server_name, username, password)?;
}
if let Some(ref home_dir) = settings.home_dir {
set_user_home_directory(server_name, username, home_dir)?;
}
if let Some(ref comment) = settings.comment {
set_user_comment(server_name, username, comment)?;
}
if let Some(flags) = settings.flags {
set_user_flags(server_name, username, flags)?;
}
if let Some(ref script_path) = settings.script_path {
set_user_script_path(server_name, username, script_path)?;
}
if let Some(ref full_name) = settings.full_name {
set_user_full_name(server_name, username, full_name)?;
}
if let Some(ref user_comment) = settings.user_comment {
set_user_user_comment(server_name, username, user_comment)?;
}
if let Some(ref workstations) = settings.workstations {
set_user_workstations(server_name, username, workstations.clone())?;
}
if let Some(acct_expires) = settings.acct_expires {
set_user_account_expiration(server_name, username, acct_expires)?;
}
if let Some(ref logon_hours) = settings.logon_hours {
set_user_logon_hours(
server_name,
username,
LogonHours::UNITS_PER_WEEK,
logon_hours.clone().into(),
)?;
}
if let Some(country_code) = settings.country_code {
set_user_country_code(server_name, username, country_code)?;
}
if let Some(primary_group_id) = settings.primary_group_id {
set_user_primary_group(server_name, username, primary_group_id)?;
}
if let Some(ref profile) = settings.profile {
set_user_profile(server_name, username, profile)?;
}
if let Some(ref home_dir_drive) = settings.home_dir_drive {
set_user_home_dir_drive(server_name, username, home_dir_drive)?;
}
if let Some(ref name) = settings.name {
set_user_name(server_name, username, name)?;
}
Ok(())
}
pub fn get_user(server_name: Option<&str>, username: &str) -> Result<User, WindowsUsersError> {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let username_w = to_wide(username);
let mut buffer = std::ptr::null_mut();
let status =
unsafe { NetUserGetInfo(server_name, PCWSTR(username_w.as_ptr()), 4, &mut buffer) };
let _guard = scopeguard::guard(buffer, |buf| {
if !buf.is_null() {
unsafe { NetApiBufferFree(Some(buf.cast())) };
}
});
net_api_result(status)?;
let user = unsafe {
let ui4 = &*(buffer as *const USER_INFO_4);
User::try_from(ui4)?
};
Ok(user.clone())
}
pub fn user_exists(server_name: Option<&str>, username: &str) -> bool {
let server_name = server_name
.map(|s| PCWSTR(to_wide(s).as_ptr()))
.unwrap_or_default();
let username_w = to_wide(username);
let mut buffer = std::ptr::null_mut();
let status =
unsafe { NetUserGetInfo(server_name, PCWSTR(username_w.as_ptr()), 0, &mut buffer) };
let _guard = scopeguard::guard(buffer, |buf| {
if !buf.is_null() {
unsafe { NetApiBufferFree(Some(buf.cast())) };
}
});
net_api_result(status).is_ok()
}