| // 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<libc::c_char>, |
| ) -> Option<String> { |
| let mut g = std::mem::MaybeUninit::<libc::group>::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(); |
| if g.gr_name.is_null() { |
| return Some(String::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<crate::GroupId>, |
| buffer: &mut Vec<libc::c_char>, |
| ) -> Vec<String> { |
| 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<User> { |
| #[inline] |
| fn parse_id(id: &str) -> Option<u32> { |
| id.parse::<u32>().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() |
| } |