mirror of
https://github.com/uutils/rust-users.git
synced 2026-06-10 15:48:37 -07:00
Merge branch 'graft'
This commit is contained in:
@@ -31,7 +31,7 @@ It does not (yet) offer *editing* functionality; the objects returned are read-o
|
||||
The function `get_current_uid` returns a `uid_t` value representing the user currently running the program, and the `get_user_by_uid` function scans the users database and returns a User object with the user’s information.
|
||||
This function returns `None` when there is no user for that ID.
|
||||
|
||||
A `User` object has the following public fields:
|
||||
A `User` object has the following accessors:
|
||||
|
||||
- **uid:** The user’s ID
|
||||
- **name:** The user’s name
|
||||
@@ -42,7 +42,7 @@ Here is a complete example that prints out the current user’s name:
|
||||
```rust
|
||||
use users::{get_user_by_uid, get_current_uid};
|
||||
let user = get_user_by_uid(get_current_uid()).unwrap();
|
||||
println!("Hello, {}!", user.name);
|
||||
println!("Hello, {}!", user.name());
|
||||
```
|
||||
|
||||
This code assumes (with `unwrap()`) that the user hasn’t been deleted after the program has started running.
|
||||
@@ -63,11 +63,11 @@ To introduce a cache, create a new `OSUsers` object and call the same methods on
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use users::{Users, OSUsers};
|
||||
let mut cache = OSUsers::empty_cache();
|
||||
use users::{Users, Groups, UsersCache};
|
||||
let mut cache = UsersCache::new();
|
||||
let uid = cache.get_current_uid();
|
||||
let user = cache.get_user_by_uid(uid).unwrap();
|
||||
println!("Hello again, {}!", user.name);
|
||||
println!("Hello again, {}!", user.name());
|
||||
```
|
||||
|
||||
This cache is **only additive**: it’s not possible to drop it, or erase selected entries, as when the database may have been modified, it’s best to start entirely afresh.
|
||||
@@ -77,22 +77,18 @@ So to accomplish this, just start using a new `OSUsers` object.
|
||||
## Groups
|
||||
|
||||
Finally, it’s possible to get groups in a similar manner.
|
||||
A `Group` object has the following public fields:
|
||||
A `Group` object has the following accessors:
|
||||
|
||||
- **gid:** The group’s ID
|
||||
- **name:** The group’s name
|
||||
- **members:** Vector of names of the users that belong to this group
|
||||
|
||||
And again, a complete example:
|
||||
|
||||
```rust
|
||||
use users::{Users, OSUsers};
|
||||
let mut cache = OSUsers::empty_cache();
|
||||
use users::{Users, Groups, UsersCache};
|
||||
let mut cache = UsersCache::new();
|
||||
let group = cache.get_group_by_name("admin").expect("No such group 'admin'!");
|
||||
println!("The '{}' group has the ID {}", group.name, group.gid);
|
||||
for member in group.members.into_iter() {
|
||||
println!("{} is a member of the group", member);
|
||||
}
|
||||
println!("The '{}' group has the ID {}", group.name(), group.gid());
|
||||
```
|
||||
|
||||
|
||||
@@ -117,19 +113,13 @@ Aside from that, you can add users and groups with `add_user` and `add_group` to
|
||||
|
||||
```rust
|
||||
use users::mock::{MockUsers, User, Group};
|
||||
use users::os::unix::{UserExt, GroupExt};
|
||||
use std::sync::Arc;
|
||||
|
||||
let mut users = MockUsers::with_current_uid(1000);
|
||||
users.add_user(User {
|
||||
uid: 1000,
|
||||
name: "Bobbins".to_string(),
|
||||
primary_group: 100,
|
||||
home_dir: "/home/bobbins".to_string(),
|
||||
shell: "/bin/bash".to_string(),
|
||||
});
|
||||
users.add_group(Group {
|
||||
gid: 100,
|
||||
name: "funkyppl".to_string(),
|
||||
members: vec![ "other_person".to_string() ]
|
||||
});
|
||||
let bobbins = User::new(1000, "Bobbins", 1000).with_home_dir("/home/bobbins");
|
||||
users.add_user(bobbins);
|
||||
users.add_group(Group::new(100, "funkyppl"));
|
||||
```
|
||||
|
||||
The exports get re-exported into the mock module, for simpler `use` lines.
|
||||
@@ -143,24 +133,19 @@ Then, you can pass in an object of either OS or Mock type.
|
||||
Here's a complete example:
|
||||
|
||||
```rust
|
||||
use users::{Users, OSUsers, User};
|
||||
use users::{Users, UsersCache, User};
|
||||
use users::os::unix::UserExt;
|
||||
use users::mock::MockUsers;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn print_current_username<U: Users>(users: &mut U) {
|
||||
println!("Current user: {:?}", users.get_current_username());
|
||||
}
|
||||
|
||||
let mut users = MockUsers::with_current_uid(1001);
|
||||
users.add_user(User {
|
||||
uid: 1001,
|
||||
name: "fred".to_string(),
|
||||
primary_group: 101,
|
||||
home_dir: "/home/fred".to_string(),
|
||||
shell: "/bin/bash".to_string(),
|
||||
});
|
||||
|
||||
users.add_user(User::new(1001, "fred", 101));
|
||||
print_current_username(&mut users);
|
||||
|
||||
let mut actual_users = OSUsers::empty_cache();
|
||||
let mut actual_users = UsersCache::new();
|
||||
print_current_username(&mut actual_users);
|
||||
```
|
||||
|
||||
+3
-12
@@ -8,17 +8,8 @@ fn main() {
|
||||
println!("Your UID is {}", current_uid);
|
||||
|
||||
let you = cache.get_user_by_uid(current_uid).expect("No entry for current user!");
|
||||
println!("Your username is {}", you.name);
|
||||
println!("Your username is {}", you.name());
|
||||
|
||||
let primary_group = cache.get_group_by_gid(you.primary_group).expect("No entry for your primary group!");
|
||||
println!("Your primary group has ID {} and name {}", primary_group.gid, primary_group.name);
|
||||
|
||||
if primary_group.members.is_empty() {
|
||||
println!("There are no other members of that group.");
|
||||
}
|
||||
else {
|
||||
for username in primary_group.members.iter() {
|
||||
println!("User {} is also a member of that group.", username);
|
||||
}
|
||||
}
|
||||
let primary_group = cache.get_group_by_gid(you.primary_group_id()).expect("No entry for your primary group!");
|
||||
println!("Your primary group has ID {} and name {}", primary_group.gid(), primary_group.name());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
extern crate users;
|
||||
use users::{Users, Groups, UsersCache};
|
||||
use users::os::unix::{UserExt, GroupExt};
|
||||
//use users::os::bsd::UserExt as BSDUserExt;
|
||||
|
||||
fn main() {
|
||||
let cache = UsersCache::new();
|
||||
|
||||
let current_uid = cache.get_current_uid();
|
||||
println!("Your UID is {}", current_uid);
|
||||
|
||||
let you = cache.get_user_by_uid(current_uid).expect("No entry for current user!");
|
||||
println!("Your username is {}", you.name());
|
||||
println!("Your shell is {}", you.shell().display());
|
||||
println!("Your home directory is {}", you.home_dir().display());
|
||||
|
||||
// The two fields below are only available on BSD systems.
|
||||
// Linux systems don’t have the fields in their `passwd` structs!
|
||||
//println!("Your password change timestamp is {}", you.password_change_time());
|
||||
//println!("Your password expiry timestamp is {}", you.password_expire_time());
|
||||
|
||||
let primary_group = cache.get_group_by_gid(you.primary_group_id()).expect("No entry for your primary group!");
|
||||
println!("Your primary group has ID {} and name {}", primary_group.gid(), primary_group.name());
|
||||
|
||||
if primary_group.members().is_empty() {
|
||||
println!("There are no other members of that group.");
|
||||
}
|
||||
else {
|
||||
for username in primary_group.members() {
|
||||
println!("User {} is also a member of that group.", username);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ fn main() {
|
||||
for uid in LO .. HI {
|
||||
let cache = cache.lock().unwrap(); // Re-unlock the mutex
|
||||
if let Some(u) = cache.get_user_by_uid(uid) { // Re-query our cache!
|
||||
println!("User #{} is {}", u.uid, u.name)
|
||||
println!("User #{} is {}", u.uid(), u.name())
|
||||
}
|
||||
else {
|
||||
println!("User #{} does not exist", uid);
|
||||
|
||||
+444
-75
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -134,7 +134,7 @@ impl Users for UsersCache {
|
||||
Vacant(entry) => {
|
||||
match super::get_user_by_uid(uid) {
|
||||
Some(user) => {
|
||||
let newsername = user.name.clone();
|
||||
let newsername = user.name_arc.clone();
|
||||
let mut users_backward = self.users.backward.borrow_mut();
|
||||
users_backward.insert(newsername, Some(uid));
|
||||
|
||||
@@ -161,7 +161,7 @@ impl Users for UsersCache {
|
||||
Vacant(entry) => {
|
||||
match super::get_user_by_name(username) {
|
||||
Some(user) => {
|
||||
let uid = user.uid;
|
||||
let uid = user.uid();
|
||||
let user_arc = Arc::new(user);
|
||||
|
||||
let mut users_forward = self.users.forward.borrow_mut();
|
||||
@@ -199,7 +199,7 @@ impl Users for UsersCache {
|
||||
|
||||
fn get_current_username(&self) -> Option<Arc<String>> {
|
||||
let uid = self.get_current_uid();
|
||||
self.get_user_by_uid(uid).map(|u| u.name.clone())
|
||||
self.get_user_by_uid(uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
|
||||
fn get_effective_uid(&self) -> uid_t {
|
||||
@@ -215,7 +215,7 @@ impl Users for UsersCache {
|
||||
|
||||
fn get_effective_username(&self) -> Option<Arc<String>> {
|
||||
let uid = self.get_effective_uid();
|
||||
self.get_user_by_uid(uid).map(|u| u.name.clone())
|
||||
self.get_user_by_uid(uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ impl Groups for UsersCache {
|
||||
let group = super::get_group_by_gid(gid);
|
||||
match group {
|
||||
Some(group) => {
|
||||
let new_group_name = group.name.clone();
|
||||
let new_group_name = group.name_arc.clone();
|
||||
let mut groups_backward = self.groups.backward.borrow_mut();
|
||||
groups_backward.insert(new_group_name, Some(gid));
|
||||
|
||||
@@ -257,7 +257,7 @@ impl Groups for UsersCache {
|
||||
match user {
|
||||
Some(group) => {
|
||||
let group_arc = Arc::new(group.clone());
|
||||
let gid = group.gid;
|
||||
let gid = group.gid();
|
||||
|
||||
let mut groups_forward = self.groups.forward.borrow_mut();
|
||||
groups_forward.insert(gid, Some(group_arc.clone()));
|
||||
@@ -294,7 +294,7 @@ impl Groups for UsersCache {
|
||||
|
||||
fn get_current_groupname(&self) -> Option<Arc<String>> {
|
||||
let gid = self.get_current_gid();
|
||||
self.get_group_by_gid(gid).map(|g| g.name.clone())
|
||||
self.get_group_by_gid(gid).map(|g| g.name_arc.clone())
|
||||
}
|
||||
|
||||
fn get_effective_gid(&self) -> gid_t {
|
||||
@@ -310,6 +310,6 @@ impl Groups for UsersCache {
|
||||
|
||||
fn get_effective_groupname(&self) -> Option<Arc<String>> {
|
||||
let gid = self.get_effective_gid();
|
||||
self.get_group_by_gid(gid).map(|g| g.name.clone())
|
||||
self.get_group_by_gid(gid).map(|g| g.name_arc.clone())
|
||||
}
|
||||
}
|
||||
|
||||
+19
-11
@@ -24,7 +24,7 @@
|
||||
//! users database and returns a User object with the user’s information. This
|
||||
//! function returns `None` when there is no user for that ID.
|
||||
//!
|
||||
//! A `User` object has the following public fields:
|
||||
//! A `User` object has the following accessors:
|
||||
//!
|
||||
//! - **uid:** The user’s ID
|
||||
//! - **name:** The user’s name
|
||||
@@ -35,7 +35,7 @@
|
||||
//! ```rust
|
||||
//! use users::{get_user_by_uid, get_current_uid};
|
||||
//! let user = get_user_by_uid(get_current_uid()).unwrap();
|
||||
//! println!("Hello, {}!", user.name);
|
||||
//! println!("Hello, {}!", user.name());
|
||||
//! ```
|
||||
//!
|
||||
//! This code assumes (with `unwrap()`) that the user hasn’t been deleted after
|
||||
@@ -68,7 +68,7 @@
|
||||
//! let mut cache = UsersCache::new();
|
||||
//! let uid = cache.get_current_uid();
|
||||
//! let user = cache.get_user_by_uid(uid).unwrap();
|
||||
//! println!("Hello again, {}!", user.name);
|
||||
//! println!("Hello again, {}!", user.name());
|
||||
//! ```
|
||||
//!
|
||||
//! This cache is **only additive**: it’s not possible to drop it, or erase
|
||||
@@ -80,22 +80,18 @@
|
||||
//! ## Groups
|
||||
//!
|
||||
//! Finally, it’s possible to get groups in a similar manner.
|
||||
//! A `Group` has the following public fields:
|
||||
//! A `Group` has the following accessors:
|
||||
//!
|
||||
//! - **gid:** The group’s ID
|
||||
//! - **name:** The group’s name
|
||||
//! - **members:** Vector of names of the users that belong to this group
|
||||
//!
|
||||
//! And again, a complete example:
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```no_run
|
||||
//! use users::{Users, Groups, UsersCache};
|
||||
//! let mut cache = UsersCache::new();
|
||||
//! let group = cache.get_group_by_name("admin").expect("No such group 'admin'!");
|
||||
//! println!("The '{}' group has the ID {}", group.name, group.gid);
|
||||
//! for member in &group.members {
|
||||
//! println!("{} is a member of the group", member);
|
||||
//! }
|
||||
//! println!("The '{}' group has the ID {}", group.name(), group.gid());
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
@@ -108,11 +104,23 @@
|
||||
//! Use the mocking module to create custom tables to test your code for these
|
||||
//! edge cases.
|
||||
|
||||
#![warn(missing_copy_implementations)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(trivial_casts, trivial_numeric_casts)]
|
||||
#![warn(unused_extern_crates, unused_qualifications)]
|
||||
|
||||
extern crate libc;
|
||||
pub use libc::{uid_t, gid_t};
|
||||
|
||||
mod base;
|
||||
pub use base::*;
|
||||
pub use base::{User, Group, os};
|
||||
pub use base::{get_user_by_uid, get_user_by_name};
|
||||
pub use base::{get_group_by_gid, get_group_by_name};
|
||||
pub use base::{get_current_uid, get_current_username};
|
||||
pub use base::{get_effective_uid, get_effective_username};
|
||||
pub use base::{get_current_gid, get_current_groupname};
|
||||
pub use base::{get_effective_gid, get_effective_groupname};
|
||||
|
||||
|
||||
pub mod cache;
|
||||
pub use cache::UsersCache;
|
||||
|
||||
+30
-27
@@ -18,11 +18,13 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use users::mock::{MockUsers, User, Group};
|
||||
//! use users::os::unix::{UserExt, GroupExt};
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
//! let mut users = MockUsers::with_current_uid(1000);
|
||||
//! users.add_user(User { uid: 1000, name: Arc::new("Bobbins".to_string()), primary_group: 100, home_dir: "/home/bobbins".to_string(), shell: "/bin/bash".to_string() });
|
||||
//! users.add_group(Group { gid: 100, name: Arc::new("funkyppl".to_string()), members: vec![ "other_person".to_string() ] });
|
||||
//! let bobbins = User::new(1000, "Bobbins", 1000).with_home_dir("/home/bobbins");
|
||||
//! users.add_user(bobbins);
|
||||
//! users.add_group(Group::new(100, "funkyppl"));
|
||||
//! ```
|
||||
//!
|
||||
//! The exports get re-exported into the mock module, for simpler `use` lines.
|
||||
@@ -38,6 +40,7 @@
|
||||
//!
|
||||
//! ```rust
|
||||
//! use users::{Users, UsersCache, User};
|
||||
//! use users::os::unix::UserExt;
|
||||
//! use users::mock::MockUsers;
|
||||
//! use std::sync::Arc;
|
||||
//!
|
||||
@@ -46,7 +49,7 @@
|
||||
//! }
|
||||
//!
|
||||
//! let mut users = MockUsers::with_current_uid(1001);
|
||||
//! users.add_user(User { uid: 1001, name: Arc::new("fred".to_string()), primary_group: 101 , home_dir: "/home/fred".to_string(), shell: "/bin/bash".to_string()});
|
||||
//! users.add_user(User::new(1001, "fred", 101));
|
||||
//! print_current_username(&mut users);
|
||||
//!
|
||||
//! let mut actual_users = UsersCache::new();
|
||||
@@ -81,12 +84,12 @@ impl MockUsers {
|
||||
|
||||
/// Add a user to the users table.
|
||||
pub fn add_user(&mut self, user: User) -> Option<Arc<User>> {
|
||||
self.users.insert(user.uid, Arc::new(user))
|
||||
self.users.insert(user.uid(), Arc::new(user))
|
||||
}
|
||||
|
||||
/// Add a group to the groups table.
|
||||
pub fn add_group(&mut self, group: Group) -> Option<Arc<Group>> {
|
||||
self.groups.insert(group.gid, Arc::new(group))
|
||||
self.groups.insert(group.gid(), Arc::new(group))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +99,7 @@ impl Users for MockUsers {
|
||||
}
|
||||
|
||||
fn get_user_by_name(&self, username: &str) -> Option<Arc<User>> {
|
||||
self.users.values().find(|u| &*u.name == username).cloned()
|
||||
self.users.values().find(|u| u.name() == username).cloned()
|
||||
}
|
||||
|
||||
fn get_current_uid(&self) -> uid_t {
|
||||
@@ -104,7 +107,7 @@ impl Users for MockUsers {
|
||||
}
|
||||
|
||||
fn get_current_username(&self) -> Option<Arc<String>> {
|
||||
self.users.get(&self.uid).map(|u| u.name.clone())
|
||||
self.users.get(&self.uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
|
||||
fn get_effective_uid(&self) -> uid_t {
|
||||
@@ -112,7 +115,7 @@ impl Users for MockUsers {
|
||||
}
|
||||
|
||||
fn get_effective_username(&self) -> Option<Arc<String>> {
|
||||
self.users.get(&self.uid).map(|u| u.name.clone())
|
||||
self.users.get(&self.uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +125,7 @@ impl Groups for MockUsers {
|
||||
}
|
||||
|
||||
fn get_group_by_name(&self, group_name: &str) -> Option<Arc<Group>> {
|
||||
self.groups.values().find(|g| &*g.name == group_name).cloned()
|
||||
self.groups.values().find(|g| g.name() == group_name).cloned()
|
||||
}
|
||||
|
||||
fn get_current_gid(&self) -> uid_t {
|
||||
@@ -130,7 +133,7 @@ impl Groups for MockUsers {
|
||||
}
|
||||
|
||||
fn get_current_groupname(&self) -> Option<Arc<String>> {
|
||||
self.groups.get(&self.uid).map(|u| u.name.clone())
|
||||
self.groups.get(&self.uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
|
||||
fn get_effective_gid(&self) -> uid_t {
|
||||
@@ -138,13 +141,13 @@ impl Groups for MockUsers {
|
||||
}
|
||||
|
||||
fn get_effective_groupname(&self) -> Option<Arc<String>> {
|
||||
self.groups.get(&self.uid).map(|u| u.name.clone())
|
||||
self.groups.get(&self.uid).map(|u| u.name_arc.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{MockUsers};
|
||||
use super::MockUsers;
|
||||
use base::{User, Group};
|
||||
use traits::{Users, Groups};
|
||||
use std::sync::Arc;
|
||||
@@ -152,7 +155,7 @@ mod test {
|
||||
#[test]
|
||||
fn current_username() {
|
||||
let mut users = MockUsers::with_current_uid(1337);
|
||||
users.add_user(User { uid: 1337, name: Arc::new("fred".to_string()), primary_group: 101, home_dir: "/home/fred".to_string(), shell: "/bin/bash".to_string() });
|
||||
users.add_user(User::new(1337, "fred", 101));
|
||||
assert_eq!(Some(Arc::new("fred".into())), users.get_current_username())
|
||||
}
|
||||
|
||||
@@ -165,54 +168,54 @@ mod test {
|
||||
#[test]
|
||||
fn uid() {
|
||||
let mut users = MockUsers::with_current_uid(0);
|
||||
users.add_user(User { uid: 1337, name: Arc::new("fred".to_string()), primary_group: 101, home_dir: "/home/fred".to_string(), shell: "/bin/bash".to_string() });
|
||||
assert_eq!(Some(Arc::new("fred".into())), users.get_user_by_uid(1337).map(|u| u.name.clone()))
|
||||
users.add_user(User::new(1337, "fred", 101));
|
||||
assert_eq!(Some(Arc::new("fred".into())), users.get_user_by_uid(1337).map(|u| u.name_arc.clone()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn username() {
|
||||
let mut users = MockUsers::with_current_uid(1337);
|
||||
users.add_user(User { uid: 1440, name: Arc::new("fred".to_string()), primary_group: 101, home_dir: "/home/fred".to_string(), shell: "/bin/bash".to_string() });
|
||||
assert_eq!(Some(1440), users.get_user_by_name("fred").map(|u| u.uid))
|
||||
users.add_user(User::new(1440, "fred", 101));
|
||||
assert_eq!(Some(1440), users.get_user_by_name("fred").map(|u| u.uid()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_username() {
|
||||
let mut users = MockUsers::with_current_uid(1337);
|
||||
users.add_user(User { uid: 1440, name: Arc::new("fred".to_string()), primary_group: 101, home_dir: "/home/fred".to_string(), shell: "/bin/bash".to_string() });
|
||||
assert_eq!(None, users.get_user_by_name("criminy").map(|u| u.uid))
|
||||
users.add_user(User::new(1337, "fred", 101));
|
||||
assert_eq!(None, users.get_user_by_name("criminy").map(|u| u.uid()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_uid() {
|
||||
let users = MockUsers::with_current_uid(0);
|
||||
assert_eq!(None, users.get_user_by_uid(1337).map(|u| u.name.clone()))
|
||||
assert_eq!(None, users.get_user_by_uid(1337).map(|u| u.name_arc.clone()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gid() {
|
||||
let mut users = MockUsers::with_current_uid(0);
|
||||
users.add_group(Group { gid: 1337, name: Arc::new("fred".to_string()), members: vec![], });
|
||||
assert_eq!(Some(Arc::new("fred".into())), users.get_group_by_gid(1337).map(|g| g.name.clone()))
|
||||
users.add_group(Group::new(1337, "fred"));
|
||||
assert_eq!(Some(Arc::new("fred".into())), users.get_group_by_gid(1337).map(|g| g.name_arc.clone()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_name() {
|
||||
let mut users = MockUsers::with_current_uid(0);
|
||||
users.add_group(Group { gid: 1337, name: Arc::new("fred".to_string()), members: vec![], });
|
||||
assert_eq!(Some(1337), users.get_group_by_name("fred").map(|g| g.gid))
|
||||
users.add_group(Group::new(1337, "fred"));
|
||||
assert_eq!(Some(1337), users.get_group_by_name("fred").map(|g| g.gid()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_group_name() {
|
||||
let mut users = MockUsers::with_current_uid(0);
|
||||
users.add_group(Group { gid: 1337, name: Arc::new("fred".to_string()), members: vec![], });
|
||||
assert_eq!(None, users.get_group_by_name("santa").map(|g| g.gid))
|
||||
users.add_group(Group::new(1337, "fred"));
|
||||
assert_eq!(None, users.get_group_by_name("santa").map(|g| g.gid()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_gid() {
|
||||
let users = MockUsers::with_current_uid(0);
|
||||
assert_eq!(None, users.get_group_by_gid(1337).map(|g| g.name.clone()))
|
||||
assert_eq!(None, users.get_group_by_gid(1337).map(|g| g.name_arc.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
+61
-26
@@ -1,3 +1,5 @@
|
||||
//! Functions for switching the running process’s user or group.
|
||||
|
||||
use std::io::{Error as IOError, Result as IOResult};
|
||||
use libc::{uid_t, gid_t, c_int};
|
||||
|
||||
@@ -16,60 +18,86 @@ extern {
|
||||
}
|
||||
|
||||
|
||||
/// Sets current user for the running process, requires root priviledges.
|
||||
/// Sets the **current user** for the running process to the one with the
|
||||
/// given user ID. Uses `setuid` internally.
|
||||
///
|
||||
/// Typically, trying to switch to anyone other than the user already running
|
||||
/// the process requires root privileges.
|
||||
pub fn set_current_uid(uid: uid_t) -> IOResult<()> {
|
||||
match unsafe { setuid(uid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("setuid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set current group for the running process, requires root priviledges.
|
||||
/// Sets the **current group** for the running process to the one with the
|
||||
/// given group ID. Uses `setgid` internally.
|
||||
///
|
||||
/// Typically, trying to switch to any group other than the group already
|
||||
/// running the process requires root privileges.
|
||||
pub fn set_current_gid(gid: gid_t) -> IOResult<()> {
|
||||
match unsafe { setgid(gid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("setgid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set effective user for the running process, requires root priviledges.
|
||||
/// Sets the **effective user** for the running process to the one with the
|
||||
/// given user ID. Uses `seteuid` internally.
|
||||
///
|
||||
/// Typically, trying to switch to anyone other than the user already running
|
||||
/// the process requires root privileges.
|
||||
pub fn set_effective_uid(uid: uid_t) -> IOResult<()> {
|
||||
match unsafe { seteuid(uid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("seteuid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set effective user for the running process, requires root priviledges.
|
||||
/// Sets the **effective group** for the running process to the one with the
|
||||
/// given group ID. Uses `setegid` internally.
|
||||
///
|
||||
/// Typically, trying to switch to any group other than the group already
|
||||
/// running the process requires root privileges.
|
||||
pub fn set_effective_gid(gid: gid_t) -> IOResult<()> {
|
||||
match unsafe { setegid(gid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("setegid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Atomically set current and effective user for the running process, requires root priviledges.
|
||||
/// Sets both the **current user** and the **effective user** for the running
|
||||
/// process to the ones with the given user IDs. Uses `setreuid` internally.
|
||||
///
|
||||
/// Typically, trying to switch to anyone other than the user already running
|
||||
/// the process requires root privileges.
|
||||
pub fn set_both_uid(ruid: uid_t, euid: uid_t) -> IOResult<()> {
|
||||
match unsafe { setreuid(ruid, euid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("setreuid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Atomically set current and effective group for the running process, requires root priviledges.
|
||||
/// Sets both the **current group** and the **effective group** for the
|
||||
/// running process to the ones with the given group IDs. Uses `setregid`
|
||||
/// internally.
|
||||
///
|
||||
/// Typically, trying to switch to any group other than the group already
|
||||
/// running the process requires root privileges.
|
||||
pub fn set_both_gid(rgid: gid_t, egid: gid_t) -> IOResult<()> {
|
||||
match unsafe { setregid(rgid, egid) } {
|
||||
0 => Ok(()),
|
||||
0 => Ok(()),
|
||||
-1 => Err(IOError::last_os_error()),
|
||||
_ => unreachable!()
|
||||
n => unreachable!("setregid returned {}", n)
|
||||
}
|
||||
}
|
||||
|
||||
/// Guard returned from a `switch_user_group` call.
|
||||
pub struct SwitchUserGuard {
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
@@ -84,21 +112,28 @@ impl Drop for SwitchUserGuard {
|
||||
}
|
||||
}
|
||||
|
||||
/// Safely switch user and group for the current scope.
|
||||
/// Requires root access.
|
||||
/// Sets the **effective user** and the **effective group** for the current
|
||||
/// scope.
|
||||
///
|
||||
/// Typically, trying to switch to any user or group other than the ones already
|
||||
/// running the process requires root privileges.
|
||||
///
|
||||
/// **Use with care!** Possible security issues can happen, as Rust doesn't
|
||||
/// guarantee running the destructor! If in doubt run `drop()` method on the
|
||||
/// guard value manually!
|
||||
///
|
||||
/// ### Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use users::switch::switch_user_group;
|
||||
///
|
||||
/// ```ignore
|
||||
/// {
|
||||
/// let _guard = switch_user_group(1001, 1001);
|
||||
/// // current and effective user and group ids are 1001
|
||||
/// }
|
||||
/// // back to the old values
|
||||
/// ```
|
||||
///
|
||||
/// Use with care! Possible security issues can happen, as Rust doesn't
|
||||
/// guarantee running the destructor! If in doubt run `drop()` method
|
||||
/// on the guard value manually!
|
||||
pub fn switch_user_group(uid: uid_t, gid: gid_t) -> Result<SwitchUserGuard, IOError> {
|
||||
pub fn switch_user_group(uid: uid_t, gid: gid_t) -> IOResult<SwitchUserGuard> {
|
||||
let current_state = SwitchUserGuard {
|
||||
uid: get_effective_uid(),
|
||||
gid: get_effective_gid(),
|
||||
|
||||
Reference in New Issue
Block a user