add group members
This commit is contained in:
parent
65542c9b69
commit
8b42c8c3b2
@ -8,6 +8,12 @@ use std::convert::TryFrom;
|
|||||||
use std::fmt::{self, Debug, Display};
|
use std::fmt::{self, Debug, Display};
|
||||||
use std::{cmp::Eq, rc::Rc};
|
use std::{cmp::Eq, rc::Rc};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
pub enum Membership {
|
||||||
|
Primary,
|
||||||
|
Member,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Groupname {
|
pub struct Groupname {
|
||||||
groupname: String,
|
groupname: String,
|
||||||
|
@ -9,12 +9,6 @@ use log::{debug, error, info, trace, warn};
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
|
||||||
pub enum GroupMembership {
|
|
||||||
Primary,
|
|
||||||
Member,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A record(line) in the user database `/etc/passwd` found in most linux systems.
|
/// A record(line) in the user database `/etc/passwd` found in most linux systems.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
@ -27,7 +21,7 @@ pub struct User {
|
|||||||
gecos: crate::Gecos, /* Real name. */
|
gecos: crate::Gecos, /* Real name. */
|
||||||
home_dir: crate::HomeDir, /* Home directory. */
|
home_dir: crate::HomeDir, /* Home directory. */
|
||||||
shell_path: crate::ShellPath, /* Shell program. */
|
shell_path: crate::ShellPath, /* Shell program. */
|
||||||
groups: Vec<(GroupMembership, crate::Group)>,
|
groups: Vec<(crate::group::Membership, crate::Group)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
@ -73,6 +67,20 @@ impl User {
|
|||||||
self.shell_path = crate::ShellPath { shell: path };
|
self.shell_path = crate::ShellPath { shell: path };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_group(
|
||||||
|
&mut self,
|
||||||
|
group_type: crate::group::Membership,
|
||||||
|
group: crate::Group,
|
||||||
|
) -> &mut Self {
|
||||||
|
self.groups.push((group_type, group));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub const fn get_groups(&self) -> &Vec<(crate::group::Membership, crate::Group)> {
|
||||||
|
&self.groups
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NewFromString for User {
|
impl NewFromString for User {
|
||||||
|
@ -90,7 +90,7 @@ impl NewFromString for Shadow {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use umanux::NewFromString;
|
/// use umanux::NewFromString;
|
||||||
/// let shad = umanux::Shadow::new_from_string(
|
/// let shad = umanux::Shadow::new_from_string(
|
||||||
/// "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::".to_string(),
|
/// "test:$6$u0Hh.9WKRF1Aeu4g$XqoDyL6Re/4ZLNQCGAXlNacxCxbdigexEqzFzkOVPV5Z1H23hlenjW8ZLgq6GQtFURYwenIFpo1c.r4aW9l5S/:18260:0:99999:7:::".to_string(),
|
||||||
/// 0,
|
/// 0,
|
||||||
/// ).unwrap();
|
/// ).unwrap();
|
||||||
/// assert_eq!(shad.get_username(), "test");
|
/// assert_eq!(shad.get_username(), "test");
|
||||||
@ -152,7 +152,7 @@ fn duration_for_days(days_source: &str) -> Option<chrono::Duration> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_and_back_identity() {
|
fn test_parse_and_back_identity() {
|
||||||
let line = "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::";
|
let line = "test:$6$u0Hh.9WKRF1Aeu4g$XqoDyL6Re/4ZLNQCGAXlNacxCxbdigexEqzFzkOVPV5Z1H23hlenjW8ZLgq6GQtFURYwenIFpo1c.r4aW9l5S/:18260:0:99999:7:::";
|
||||||
let line2 = Shadow::new_from_string(line.to_owned(), 0).unwrap();
|
let line2 = Shadow::new_from_string(line.to_owned(), 0).unwrap();
|
||||||
assert_eq!(format!("{}", line2), line);
|
assert_eq!(format!("{}", line2), line);
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,12 @@ use std::collections::HashMap;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
|
|
||||||
|
pub type UserList = HashMap<String, crate::User>;
|
||||||
|
|
||||||
pub struct UserDBLocal {
|
pub struct UserDBLocal {
|
||||||
source_files: files::Files,
|
source_files: files::Files,
|
||||||
source_hashes: hashes::Hashes, // to detect changes
|
source_hashes: hashes::Hashes, // to detect changes
|
||||||
pub users: HashMap<String, crate::User>,
|
pub users: UserList,
|
||||||
pub groups: Vec<crate::Group>,
|
pub groups: Vec<crate::Group>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +66,7 @@ impl UserDBLocal {
|
|||||||
let passwds: Vec<crate::Shadow> = string_to(&my_shadow_lines);
|
let passwds: Vec<crate::Shadow> = string_to(&my_shadow_lines);
|
||||||
let groups: Vec<crate::Group> = string_to(&my_group_lines);
|
let groups: Vec<crate::Group> = string_to(&my_group_lines);
|
||||||
shadow_to_users(&mut users, passwds);
|
shadow_to_users(&mut users, passwds);
|
||||||
|
groups_to_users(&mut users, &groups);
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
source_files: files,
|
source_files: files,
|
||||||
users,
|
users,
|
||||||
@ -346,11 +349,41 @@ fn file_to_string(file: &File) -> Result<String, crate::UserLibError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn groups_to_users<'a>(users: &'a mut UserList, groups: &'a [crate::Group]) -> &'a mut UserList {
|
||||||
|
for group in groups {
|
||||||
|
match group.get_member_names() {
|
||||||
|
Some(usernames) => {
|
||||||
|
for username in usernames {
|
||||||
|
if let Some(user) = users.get_mut(username) {
|
||||||
|
user.add_group(crate::group::Membership::Member, group.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for user in users.values_mut() {
|
||||||
|
let gid = user.get_gid();
|
||||||
|
let grouplist: Vec<&crate::Group> = groups
|
||||||
|
.iter()
|
||||||
|
.filter(|g| g.get_gid().unwrap() == gid)
|
||||||
|
.collect();
|
||||||
|
if grouplist.len() == 1 {
|
||||||
|
let group = *grouplist.first().unwrap();
|
||||||
|
user.add_group(crate::group::Membership::Primary, group.clone());
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Somehow the group with gid {} was found {} times",
|
||||||
|
gid,
|
||||||
|
grouplist.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users
|
||||||
|
}
|
||||||
|
|
||||||
/// Merge the Shadow passwords into the users
|
/// Merge the Shadow passwords into the users
|
||||||
fn shadow_to_users(
|
fn shadow_to_users(users: &mut UserList, shadow: Vec<crate::Shadow>) -> &mut UserList {
|
||||||
users: &mut HashMap<String, crate::User>,
|
|
||||||
shadow: Vec<crate::Shadow>,
|
|
||||||
) -> &mut HashMap<String, crate::User> {
|
|
||||||
for pass in shadow {
|
for pass in shadow {
|
||||||
let user = users
|
let user = users
|
||||||
.get_mut(pass.get_username())
|
.get_mut(pass.get_username())
|
||||||
@ -360,8 +393,8 @@ fn shadow_to_users(
|
|||||||
users
|
users
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a `Vec<crate::User>` to a `HashMap<String, crate::User>` where the username is used as key
|
/// Convert a `Vec<crate::User>` to a `UserList` (`HashMap<String, crate::User>`) where the username is used as key
|
||||||
fn user_vec_to_hashmap(users: Vec<crate::User>) -> HashMap<String, crate::User> {
|
fn user_vec_to_hashmap(users: Vec<crate::User>) -> UserList {
|
||||||
users
|
users
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
@ -413,11 +446,17 @@ where
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_creator_user_db_local() {
|
fn test_creator_user_db_local() {
|
||||||
let data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::", "teste:x:1002:test,test");
|
let data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:$6$u0Hh.9WKRF1Aeu4g$XqoDyL6Re/4ZLNQCGAXlNacxCxbdigexEqzFzkOVPV5Z1H23hlenjW8ZLgq6GQtFURYwenIFpo1c.r4aW9l5S/:18260:0:99999:7:::", "teste:x:1002:test,test");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
data.users.get("test").unwrap().get_username().unwrap(),
|
data.users.get("test").unwrap().get_username().unwrap(),
|
||||||
"test"
|
"test"
|
||||||
)
|
);
|
||||||
|
for user in data.users.values() {
|
||||||
|
if let Some((member, group)) = user.get_groups().first() {
|
||||||
|
assert_eq!(*member, crate::group::Membership::Member);
|
||||||
|
assert_eq!(group.get_groupname(), Some("teste"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -465,7 +504,7 @@ fn test_user_db_read_implementation() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_user_db_write_implementation() {
|
fn test_user_db_write_implementation() {
|
||||||
use crate::api::DeleteUserArgs;
|
use crate::api::DeleteUserArgs;
|
||||||
let mut data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:!!$6$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::", "teste:x:1002:test,test");
|
let mut data = UserDBLocal::import_from_strings("test:x:1001:1001:full Name,004,000342,001-2312,myemail@test.com:/home/test:/bin/test", "test:$6$u0Hh.9WKRF1Aeu4g$XqoDyL6Re/4ZLNQCGAXlNacxCxbdigexEqzFzkOVPV5Z1H23hlenjW8ZLgq6GQtFURYwenIFpo1c.r4aW9l5S/:18260:0:99999:7:::", "teste:x:1002:test,test");
|
||||||
let user = "test";
|
let user = "test";
|
||||||
|
|
||||||
assert_eq!(data.get_all_users().len(), 1);
|
assert_eq!(data.get_all_users().len(), 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user