1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{
4 common::{Gid, Uid},
5 User,
6};
7
8use libc::{getgrgid_r, getgrouplist};
9use std::fs::File;
10use std::io::Read;
11
12pub(crate) unsafe fn get_group_name(
13 id: libc::gid_t,
14 buffer: &mut Vec<libc::c_char>,
15) -> Option<String> {
16 let mut g = std::mem::MaybeUninit::<libc::group>::uninit();
17 let mut tmp_ptr = std::ptr::null_mut();
18 let mut last_errno = 0;
19 loop {
20 if retry_eintr!(set_to_0 => last_errno => getgrgid_r(
21 id as _,
22 g.as_mut_ptr() as _,
23 buffer.as_mut_ptr(),
24 buffer.capacity() as _,
25 &mut tmp_ptr as _
26 )) != 0
27 {
28 // If there was not enough memory, we give it more.
29 if last_errno == libc::ERANGE as _ {
30 buffer.reserve(2048);
31 continue;
32 }
33 return None;
34 }
35 break;
36 }
37 let g = g.assume_init();
38 let mut group_name = Vec::new();
39 if g.gr_name.is_null() {
40 return Some(String::new());
41 }
42 let c_group_name = g.gr_name;
43 let mut x = 0;
44 loop {
45 let c = *c_group_name.offset(x);
46 if c == 0 {
47 break;
48 }
49 group_name.push(c as u8);
50 x += 1;
51 }
52 String::from_utf8(group_name).ok()
53}
54
55pub(crate) unsafe fn get_user_groups(
56 name: *const libc::c_char,
57 group_id: libc::gid_t,
58 groups: &mut Vec<crate::GroupId>,
59 buffer: &mut Vec<libc::c_char>,
60) -> Vec<String> {
61 loop {
62 let mut nb_groups: usize = groups.capacity();
63 if getgrouplist(
64 user:name,
65 group_id as _,
66 groups:groups.as_mut_ptr(),
67 &mut nb_groups as *mut _ as *mut _,
68 ) == -1
69 {
70 groups.reserve(additional:256);
71 continue;
72 }
73 groups.set_len(new_len:nb_groups as _);
74 return groupsimpl Iterator
75 .iter()
76 .filter_map(|group_id: &u32| crate::users::get_group_name(*group_id as _, buffer))
77 .collect();
78 }
79}
80
81// Not used by mac.
82#[allow(unused)]
83pub(crate) fn get_users_list() -> Vec<User> {
84 #[inline]
85 fn parse_id(id: &str) -> Option<u32> {
86 id.parse::<u32>().ok()
87 }
88
89 let mut s = String::new();
90 let mut buffer = Vec::with_capacity(2048);
91 let mut groups = Vec::with_capacity(256);
92
93 let _ = File::open("/etc/passwd").and_then(|mut f| f.read_to_string(&mut s));
94 s.lines()
95 .filter_map(|line| {
96 let mut parts = line.split(':');
97 if let Some(username) = parts.next() {
98 let mut parts = parts.skip(1);
99 // Skip the user if the uid cannot be parsed correctly
100 if let Some(uid) = parts.next().and_then(parse_id) {
101 if let Some(group_id) = parts.next().and_then(parse_id) {
102 let mut c_user = username.as_bytes().to_vec();
103 c_user.push(0);
104 // Let's get all the group names!
105 return Some(User {
106 uid: Uid(uid),
107 gid: Gid(group_id),
108 name: username.to_owned(),
109 groups: unsafe {
110 get_user_groups(
111 c_user.as_ptr() as *const _,
112 group_id,
113 &mut groups,
114 &mut buffer,
115 )
116 },
117 });
118 }
119 }
120 }
121 None
122 })
123 .collect()
124}
125