//! passwd queries use super::*; use std::sync::Mutex; use libc::{ getpwent, endpwent }; /// Safe wrapper around C's passwd struct. Doesn't implement the /// `passwd', `gecos' or `expire' fields because we don't use them. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Passwd { name: String, uid: u32, gid: u32, home: String, shell: String, } /// Returns a vector of the system's users pub fn get_users() -> std::vec::Vec { lazy_static::lazy_static! { static ref MUTEX: Mutex<()> = Mutex::new(()); } let mut users = vec!(); unsafe { // This could maybe be simplified but there's no point macro_rules! from_cstr { ($x:expr, $fmt:literal) => { match std::ffi::CStr::from_ptr($x).to_owned().into_string() { Ok(v) => v, Err(v) => { warn!($fmt, v); continue; } } }; ($x:expr, $fmt:literal, $usr:expr) => { match std::ffi::CStr::from_ptr($x).to_owned().into_string() { Ok(v) => v, Err(v) => { warn!($fmt, $usr, v); continue; } } } } let _lock = MUTEX.lock().expect("poisoned"); loop { let passwd = getpwent(); // FFI returns NULL when no more entries if passwd.is_null() { break; } let my_passwd = *passwd; let name = from_cstr!( my_passwd.pw_name, "User {} has invalid UTF-8 characters, skipping" ); users.push(Passwd{ gid: 1, uid: 2, home: from_cstr!( my_passwd.pw_dir, "User {}'s home ({}) has invalid UTF-8 characters, skipping", name ), shell: from_cstr!( my_passwd.pw_shell, "User {}'s shell ({}) has invalid UTF-8 characters, skipping", name ), name }); } endpwent(); } return users; }