1 //! A cache for users and groups provided by the OS.
2 //!
3 //! Because the users table changes so infrequently, it's common for
4 //! short-running programs to cache the results instead of getting the most
5 //! up-to-date entries every time. The [`UsersCache`](struct.UsersCache.html)
6 //! type helps with this, providing methods that have the same name as the
7 //! others in this crate, only they store the results.
8 //!
9 //! ## Example
10 //!
11 //! ```no_run
12 //! use std::sync::Arc;
13 //! use users::{Users, UsersCache};
14 //!
15 //! let mut cache = UsersCache::new();
16 //! let user      = cache.get_user_by_uid(502).expect("User not found");
17 //! let same_user = cache.get_user_by_uid(502).unwrap();
18 //!
19 //! // The two returned values point to the same User
20 //! assert!(Arc::ptr_eq(&user, &same_user));
21 //! ```
22 //!
23 //! ## Caching, multiple threads, and mutability
24 //!
25 //! The `UsersCache` type is caught between a rock and a hard place when it
26 //! comes to providing references to users and groups.
27 //!
28 //! Instead of returning a fresh `User` struct each time, for example, it will
29 //! return a reference to the version it currently has in its cache. So you can
30 //! ask for User #501 twice, and you’ll get a reference to the same value both
31 //! time. Its methods are *idempotent* -- calling one multiple times has the
32 //! same effect as calling one once.
33 //!
34 //! This works fine in theory, but in practice, the cache has to update its own
35 //! state somehow: it contains several `HashMap`s that hold the result of user
36 //! and group lookups. Rust provides mutability in two ways:
37 //!
38 //! 1. Have its methods take `&mut self`, instead of `&self`, allowing the
39 //!   internal maps to be mutated (“inherited mutability”)
40 //! 2. Wrap the internal maps in a `RefCell`, allowing them to be modified
41 //!   (“interior mutability”).
42 //!
43 //! Unfortunately, Rust is also very protective of references to a mutable
44 //! value. In this case, switching to `&mut self` would only allow for one user
45 //! to be read at a time!
46 //!
47 //! ```no_run
48 //! use users::{Users, Groups, UsersCache};
49 //!
50 //! let mut cache = UsersCache::new();
51 //!
52 //! let uid   = cache.get_current_uid();                          // OK...
53 //! let user  = cache.get_user_by_uid(uid).unwrap();              // OK...
54 //! let group = cache.get_group_by_gid(user.primary_group_id());  // No!
55 //! ```
56 //!
57 //! When we get the `user`, it returns an optional reference (which we unwrap)
58 //! to the user’s entry in the cache. This is a reference to something contained
59 //! in a mutable value. Then, when we want to get the user’s primary group, it
60 //! will return *another* reference to the same mutable value. This is something
61 //! that Rust explicitly disallows!
62 //!
63 //! The compiler wasn’t on our side with Option 1, so let’s try Option 2:
64 //! changing the methods back to `&self` instead of `&mut self`, and using
65 //! `RefCell`s internally. However, Rust is smarter than this, and knows that
66 //! we’re just trying the same trick as earlier. A simplified implementation of
67 //! a user cache lookup would look something like this:
68 //!
69 //! ```text
70 //! fn get_user_by_uid(&self, uid: uid_t) -> Option<&User> {
71 //!     let users = self.users.borrow_mut();
72 //!     users.get(uid)
73 //! }
74 //! ```
75 //!
76 //! Rust won’t allow us to return a reference like this because the `Ref` of the
77 //! `RefCell` just gets dropped at the end of the method, meaning that our
78 //! reference does not live long enough.
79 //!
80 //! So instead of doing any of that, we use `Arc` everywhere in order to get
81 //! around all the lifetime restrictions. Returning reference-counted users and
82 //! groups mean that we don’t have to worry about further uses of the cache, as
83 //! the values themselves don’t count as being stored *in* the cache anymore. So
84 //! it can be queried multiple times or go out of scope and the values it
85 //! produces are not affected.
86 
87 use libc::{uid_t, gid_t};
88 use std::cell::{Cell, RefCell};
89 use std::collections::hash_map::Entry::{Occupied, Vacant};
90 use std::collections::HashMap;
91 use std::ffi::OsStr;
92 use std::sync::Arc;
93 
94 use base::{User, Group, all_users};
95 use traits::{Users, Groups};
96 
97 
98 /// A producer of user and group instances that caches every result.
99 ///
100 /// For more information, see the [`users::cache` module documentation](index.html).
101 pub struct UsersCache {
102     users:  BiMap<uid_t, User>,
103     groups: BiMap<gid_t, Group>,
104 
105     uid:  Cell<Option<uid_t>>,
106     gid:  Cell<Option<gid_t>>,
107     euid: Cell<Option<uid_t>>,
108     egid: Cell<Option<gid_t>>,
109 }
110 
111 /// A kinda-bi-directional `HashMap` that associates keys to values, and
112 /// then strings back to keys.
113 ///
114 /// It doesn’t go the full route and offer *values*-to-keys lookup, because we
115 /// only want to search based on usernames and group names. There wouldn’t be
116 /// much point offering a “User to uid” map, as the uid is present in the
117 /// `User` struct!
118 struct BiMap<K, V> {
119     forward:  RefCell< HashMap<K, Option<Arc<V>>> >,
120     backward: RefCell< HashMap<Arc<OsStr>, Option<K>> >,
121 }
122 
123 
124 // Default has to be impl’d manually here, because there’s no
125 // Default impl on User or Group, even though those types aren’t
126 // needed to produce a default instance of any HashMaps...
127 impl Default for UsersCache {
default() -> Self128     fn default() -> Self {
129         Self {
130             users: BiMap {
131                 forward:  RefCell::new(HashMap::new()),
132                 backward: RefCell::new(HashMap::new()),
133             },
134 
135             groups: BiMap {
136                 forward:  RefCell::new(HashMap::new()),
137                 backward: RefCell::new(HashMap::new()),
138             },
139 
140             uid:  Cell::new(None),
141             gid:  Cell::new(None),
142             euid: Cell::new(None),
143             egid: Cell::new(None),
144         }
145     }
146 }
147 
148 
149 impl UsersCache {
150 
151     /// Creates a new empty cache.
152     ///
153     /// # Examples
154     ///
155     /// ```
156     /// use users::cache::UsersCache;
157     ///
158     /// let cache = UsersCache::new();
159     /// ```
new() -> Self160     pub fn new() -> Self {
161         Self::default()
162     }
163 
164     /// Creates a new cache that contains all the users present on the system.
165     ///
166     /// # Safety
167     ///
168     /// This is `unsafe` because we cannot prevent data races if two caches
169     /// were attempted to be initialised on different threads at the same time.
170     /// For more information, see the [`all_users` documentation](../fn.all_users.html).
171     ///
172     /// # Examples
173     ///
174     /// ```
175     /// use users::cache::UsersCache;
176     ///
177     /// let cache = unsafe { UsersCache::with_all_users() };
178     /// ```
with_all_users() -> Self179     pub unsafe fn with_all_users() -> Self {
180         let cache = Self::new();
181 
182         for user in all_users() {
183             let uid = user.uid();
184             let user_arc = Arc::new(user);
185             cache.users.forward.borrow_mut().insert(uid, Some(Arc::clone(&user_arc)));
186             cache.users.backward.borrow_mut().insert(Arc::clone(&user_arc.name_arc), Some(uid));
187         }
188 
189         cache
190     }
191 }
192 
193 
194 // TODO: stop using ‘Arc::from’ with entry API
195 // The ‘get_*_by_name’ functions below create a new Arc before even testing if
196 // the user exists in the cache, essentially creating an unnecessary Arc.
197 // https://internals.rust-lang.org/t/pre-rfc-abandonning-morals-in-the-name-of-performance-the-raw-entry-api/7043/51
198 // https://github.com/rust-lang/rfcs/pull/1769
199 
200 
201 impl Users for UsersCache {
get_user_by_uid(&self, uid: uid_t) -> Option<Arc<User>>202     fn get_user_by_uid(&self, uid: uid_t) -> Option<Arc<User>> {
203         let mut users_forward = self.users.forward.borrow_mut();
204 
205         let entry = match users_forward.entry(uid) {
206             Vacant(e) => e,
207             Occupied(e) => return e.get().as_ref().map(Arc::clone),
208         };
209 
210         if let Some(user) = super::get_user_by_uid(uid) {
211             let newsername = Arc::clone(&user.name_arc);
212             let mut users_backward = self.users.backward.borrow_mut();
213             users_backward.insert(newsername, Some(uid));
214 
215             let user_arc = Arc::new(user);
216             entry.insert(Some(Arc::clone(&user_arc)));
217             Some(user_arc)
218         }
219         else {
220             entry.insert(None);
221             None
222         }
223     }
224 
get_user_by_name<S: AsRef<OsStr> + ?Sized>(&self, username: &S) -> Option<Arc<User>>225     fn get_user_by_name<S: AsRef<OsStr> + ?Sized>(&self, username: &S) -> Option<Arc<User>> {
226         let mut users_backward = self.users.backward.borrow_mut();
227 
228         let entry = match users_backward.entry(Arc::from(username.as_ref())) {
229             Vacant(e) => e,
230             Occupied(e) => {
231                 return (*e.get()).and_then(|uid| {
232                     let users_forward = self.users.forward.borrow_mut();
233                     users_forward[&uid].as_ref().map(Arc::clone)
234                 })
235             }
236         };
237 
238         if let Some(user) = super::get_user_by_name(username) {
239             let uid = user.uid();
240             let user_arc = Arc::new(user);
241 
242             let mut users_forward = self.users.forward.borrow_mut();
243             users_forward.insert(uid, Some(Arc::clone(&user_arc)));
244             entry.insert(Some(uid));
245 
246             Some(user_arc)
247         }
248         else {
249             entry.insert(None);
250             None
251         }
252     }
253 
get_current_uid(&self) -> uid_t254     fn get_current_uid(&self) -> uid_t {
255         self.uid.get().unwrap_or_else(|| {
256             let uid = super::get_current_uid();
257             self.uid.set(Some(uid));
258             uid
259         })
260     }
261 
get_current_username(&self) -> Option<Arc<OsStr>>262     fn get_current_username(&self) -> Option<Arc<OsStr>> {
263         let uid = self.get_current_uid();
264         self.get_user_by_uid(uid).map(|u| Arc::clone(&u.name_arc))
265     }
266 
get_effective_uid(&self) -> uid_t267     fn get_effective_uid(&self) -> uid_t {
268         self.euid.get().unwrap_or_else(|| {
269             let uid = super::get_effective_uid();
270             self.euid.set(Some(uid));
271             uid
272         })
273     }
274 
get_effective_username(&self) -> Option<Arc<OsStr>>275     fn get_effective_username(&self) -> Option<Arc<OsStr>> {
276         let uid = self.get_effective_uid();
277         self.get_user_by_uid(uid).map(|u| Arc::clone(&u.name_arc))
278     }
279 }
280 
281 
282 impl Groups for UsersCache {
get_group_by_gid(&self, gid: gid_t) -> Option<Arc<Group>>283     fn get_group_by_gid(&self, gid: gid_t) -> Option<Arc<Group>> {
284         let mut groups_forward = self.groups.forward.borrow_mut();
285 
286         let entry = match groups_forward.entry(gid) {
287             Vacant(e) => e,
288             Occupied(e) => return e.get().as_ref().map(Arc::clone),
289         };
290 
291         if let Some(group) = super::get_group_by_gid(gid) {
292             let new_group_name = Arc::clone(&group.name_arc);
293             let mut groups_backward = self.groups.backward.borrow_mut();
294             groups_backward.insert(new_group_name, Some(gid));
295 
296             let group_arc = Arc::new(group);
297             entry.insert(Some(Arc::clone(&group_arc)));
298             Some(group_arc)
299         }
300         else {
301             entry.insert(None);
302             None
303         }
304     }
305 
get_group_by_name<S: AsRef<OsStr> + ?Sized>(&self, group_name: &S) -> Option<Arc<Group>>306     fn get_group_by_name<S: AsRef<OsStr> + ?Sized>(&self, group_name: &S) -> Option<Arc<Group>> {
307         let mut groups_backward = self.groups.backward.borrow_mut();
308 
309         let entry = match groups_backward.entry(Arc::from(group_name.as_ref())) {
310             Vacant(e) => e,
311             Occupied(e) => {
312                 return (*e.get()).and_then(|gid| {
313                     let groups_forward = self.groups.forward.borrow_mut();
314                     groups_forward[&gid].as_ref().cloned()
315                 });
316             }
317         };
318 
319         if let Some(group) = super::get_group_by_name(group_name) {
320             let group_arc = Arc::new(group.clone());
321             let gid = group.gid();
322 
323             let mut groups_forward = self.groups.forward.borrow_mut();
324             groups_forward.insert(gid, Some(Arc::clone(&group_arc)));
325             entry.insert(Some(gid));
326 
327             Some(group_arc)
328         }
329         else {
330             entry.insert(None);
331             None
332         }
333     }
334 
get_current_gid(&self) -> gid_t335     fn get_current_gid(&self) -> gid_t {
336         self.gid.get().unwrap_or_else(|| {
337             let gid = super::get_current_gid();
338             self.gid.set(Some(gid));
339             gid
340         })
341     }
342 
get_current_groupname(&self) -> Option<Arc<OsStr>>343     fn get_current_groupname(&self) -> Option<Arc<OsStr>> {
344         let gid = self.get_current_gid();
345         self.get_group_by_gid(gid).map(|g| Arc::clone(&g.name_arc))
346     }
347 
get_effective_gid(&self) -> gid_t348     fn get_effective_gid(&self) -> gid_t {
349         self.egid.get().unwrap_or_else(|| {
350             let gid = super::get_effective_gid();
351             self.egid.set(Some(gid));
352             gid
353         })
354     }
355 
get_effective_groupname(&self) -> Option<Arc<OsStr>>356     fn get_effective_groupname(&self) -> Option<Arc<OsStr>> {
357         let gid = self.get_effective_gid();
358         self.get_group_by_gid(gid).map(|g| Arc::clone(&g.name_arc))
359     }
360 }
361