1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use crate::{ |
4 | common::{Gid, Uid}, |
5 | User, |
6 | }; |
7 | |
8 | use libc::{getgrgid_r, getgrouplist}; |
9 | use std::fs::File; |
10 | use std::io::Read; |
11 | |
12 | pub(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 | |
55 | pub(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)] |
83 | pub(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 | |