diff --git a/libs/users/src/lib.rs b/libs/users/src/lib.rs index 0b3962ef5..695474ea6 100644 --- a/libs/users/src/lib.rs +++ b/libs/users/src/lib.rs @@ -1,4 +1,8 @@ +use libc::passwd as c_passwd; use libc::{gid_t, uid_t}; +use std::ffi::{CStr, OsStr, OsString}; +use std::os::unix::ffi::OsStrExt; +use std::{mem, ptr}; pub fn get_current_uid() -> uid_t { unsafe { libc::getuid() } @@ -15,3 +19,41 @@ pub fn get_current_gid() -> gid_t { pub fn get_effective_gid() -> gid_t { unsafe { libc::getegid() } } + +pub fn get_user_name_by_uid(uid: uid_t) -> Option { + let mut passwd = unsafe { mem::zeroed::() }; + let mut buf = vec![0; 2048]; + let mut result = ptr::null_mut::(); + + #[cfg(feature = "logging")] + trace!("Running getpwuid_r for user #{}", uid); + + loop { + let r = + unsafe { libc::getpwuid_r(uid, &mut passwd, buf.as_mut_ptr(), buf.len(), &mut result) }; + + if r != libc::ERANGE { + break; + } + + let newsize = buf.len().checked_mul(2)?; + buf.resize(newsize, 0); + } + + if result.is_null() { + // There is no such user, or an error has occurred. + // errno gets set if there’s an error. + return None; + } + + if result != &mut passwd { + // The result of getpwuid_r should be its input passwd. + return None; + } + + let name = unsafe { + OsStr::from_bytes(CStr::from_ptr(result.read().pw_name).to_bytes()).to_os_string() + }; + + Some(name) +} diff --git a/unix_integration/src/selinux_util.rs b/unix_integration/src/selinux_util.rs index c56c3b71c..742069503 100644 --- a/unix_integration/src/selinux_util.rs +++ b/unix_integration/src/selinux_util.rs @@ -1,7 +1,7 @@ +use kanidm_utils_users::get_user_name_by_uid; use std::ffi::CString; use std::path::Path; use std::process::Command; -use users::get_user_by_uid; use selinux::{ current_mode, kernel_support, label::back_end::File, label::Labeler, KernelSupport, @@ -63,8 +63,8 @@ impl SelinuxLabeler { // so that relabels in the future do not break it. #[cfg(all(target_family = "unix", feature = "selinux"))] // Yes, gid, because we use the GID number for both the user's UID and primary GID - let sel_lookup_path_raw = match get_user_by_uid(gid) { - Some(v) => format!("{}{}", home_prefix, v.name().to_str().unwrap()), + let sel_lookup_path_raw = match get_user_name_by_uid(gid) { + Some(v) => format!("{}{}", home_prefix, v.to_str().unwrap()), None => { return Err("Failed looking up username by uid for SELinux relabeling".to_string()); }