// Take a look at the license at the top of the repository in the LICENSE file. use crate::{ common::{Gid, Uid}, User, }; use libc::{getgrgid_r, getgrouplist}; use std::fs::File; use std::io::Read; pub(crate) unsafe fn get_group_name( id: libc::gid_t, buffer: &mut Vec, ) -> Option { let mut g = std::mem::MaybeUninit::::uninit(); let mut tmp_ptr = std::ptr::null_mut(); let mut last_errno = 0; loop { if retry_eintr!(set_to_0 => last_errno => getgrgid_r( id as _, g.as_mut_ptr() as _, buffer.as_mut_ptr(), buffer.capacity() as _, &mut tmp_ptr as _ )) != 0 { // If there was not enough memory, we give it more. if last_errno == libc::ERANGE as _ { buffer.reserve(2048); continue; } return None; } break; } let g = g.assume_init(); let mut group_name = Vec::new(); let c_group_name = g.gr_name; let mut x = 0; loop { let c = *c_group_name.offset(x); if c == 0 { break; } group_name.push(c as u8); x += 1; } String::from_utf8(group_name).ok() } pub(crate) unsafe fn get_user_groups( name: *const libc::c_char, group_id: libc::gid_t, groups: &mut Vec, buffer: &mut Vec, ) -> Vec { loop { let mut nb_groups = groups.capacity(); if getgrouplist( name, group_id as _, groups.as_mut_ptr(), &mut nb_groups as *mut _ as *mut _, ) == -1 { groups.reserve(256); continue; } groups.set_len(nb_groups as _); return groups .iter() .filter_map(|group_id| crate::users::get_group_name(*group_id as _, buffer)) .collect(); } } // Not used by mac. #[allow(unused)] pub(crate) fn get_users_list() -> Vec { #[inline] fn parse_id(id: &str) -> Option { id.parse::().ok() } let mut s = String::new(); let mut buffer = Vec::with_capacity(2048); let mut groups = Vec::with_capacity(256); let _ = File::open("/etc/passwd").and_then(|mut f| f.read_to_string(&mut s)); s.lines() .filter_map(|line| { let mut parts = line.split(':'); if let Some(username) = parts.next() { let mut parts = parts.skip(1); // Skip the user if the uid cannot be parsed correctly if let Some(uid) = parts.next().and_then(parse_id) { if let Some(group_id) = parts.next().and_then(parse_id) { let mut c_user = username.as_bytes().to_vec(); c_user.push(0); // Let's get all the group names! return Some(User { uid: Uid(uid), gid: Gid(group_id), name: username.to_owned(), groups: unsafe { get_user_groups( c_user.as_ptr() as *const _, group_id, &mut groups, &mut buffer, ) }, }); } } } None }) .collect() }