diff --git a/src/api/mod.rs b/src/api/mod.rs index 23b6bef..42f9ffb 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -7,7 +7,7 @@ pub trait UserDBRead { fn get_all_users(&self) -> Vec<&crate::User>; fn get_user_by_name(&self, name: &str) -> Option<&crate::User>; fn get_user_by_id(&self, uid: u32) -> Option<&crate::User>; - fn get_all_groups(&self) -> Vec<&crate::Group>; + fn get_all_groups(&self) -> Vec; fn get_group_by_name(&self, name: &str) -> Option<&crate::Group>; fn get_group_by_id(&self, name: u32) -> Option<&crate::Group>; } diff --git a/src/group/mod.rs b/src/group/mod.rs index 88aae1a..8be57fe 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -4,9 +4,9 @@ use crate::userlib::NewFromString; use log::warn; use crate::UserLibError; -use std::cmp::Eq; use std::convert::TryFrom; use std::fmt::{self, Debug, Display}; +use std::{cmp::Eq, rc::Rc}; #[derive(Debug, PartialEq, Eq)] pub struct Groupname { @@ -38,9 +38,10 @@ pub(crate) fn is_groupname_valid(name: &str) -> bool { crate::user::passwd_fields::is_username_valid(name) } +pub type Group = Rc; /// A record(line) in the user database `/etc/shadow` found in most linux systems. #[derive(Debug, PartialEq, Eq)] -pub struct Group { +pub struct Inner { pos: u32, source: String, groupname: Groupname, /* Username. */ @@ -49,7 +50,7 @@ pub struct Group { members: Vec, /* Real name. */ } -impl Group { +impl Inner { #[must_use] pub fn remove_in(&self, content: &str) -> String { content @@ -61,7 +62,7 @@ impl Group { } use crate::api::GroupRead; -impl GroupRead for Group { +impl GroupRead for Inner { #[must_use] fn get_groupname(&self) -> Option<&str> { Some(&self.groupname.groupname) @@ -84,7 +85,7 @@ impl GroupRead for Group { } } -impl Display for Group { +impl Display for Inner { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!( f, @@ -101,7 +102,7 @@ impl Display for Group { } } -impl NewFromString for Group { +impl NewFromString for Rc { /// Parse a line formatted like one in `/etc/group` and construct a matching [`Group`] instance /// /// # Example @@ -120,14 +121,14 @@ impl NewFromString for Group { fn new_from_string(line: String, position: u32) -> Result { let elements: Vec = line.split(':').map(ToString::to_string).collect(); if elements.len() == 4 { - Ok(Self { + Ok(Self::new(Inner { pos: position, source: line, groupname: Groupname::try_from(elements.get(0).unwrap().to_string())?, password: crate::Password::Disabled, gid: crate::Gid::try_from(elements.get(2).unwrap().to_string())?, members: parse_members_list(elements.get(3).unwrap()), - }) + })) } else { Err(format!( "Failed to parse: not enough elements ({}): {:?}", @@ -156,7 +157,7 @@ fn parse_members_list(source: &str) -> Vec { #[test] fn test_parse_and_back_identity() { let line = "teste:x:1002:test,teste"; - let line2 = Group::new_from_string(line.to_owned(), 0).unwrap(); + let line2: Group = Group::new_from_string(line.to_owned(), 0).unwrap(); assert_eq!(format!("{}", line2), line); } diff --git a/src/user/mod.rs b/src/user/mod.rs index 506611f..0b3285c 100644 --- a/src/user/mod.rs +++ b/src/user/mod.rs @@ -9,6 +9,12 @@ use log::{debug, error, info, trace, warn}; use std::convert::TryFrom; 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. #[derive(Debug, PartialEq, Eq, Clone)] pub struct User { @@ -21,6 +27,7 @@ pub struct User { gecos: crate::Gecos, /* Real name. */ home_dir: crate::HomeDir, /* Home directory. */ shell_path: crate::ShellPath, /* Shell program. */ + groups: Vec<(GroupMembership, crate::Group)>, } impl User { @@ -100,6 +107,7 @@ impl NewFromString for User { gecos: crate::Gecos::try_from(elements.get(4).unwrap().to_string())?, home_dir: crate::HomeDir::try_from(elements.get(5).unwrap().to_string())?, shell_path: crate::ShellPath::try_from(elements.get(6).unwrap().to_string())?, + groups: Vec::new(), }) } else { Err("Failed to parse: not enough elements".into()) @@ -204,6 +212,7 @@ impl Default for User { shell_path: crate::ShellPath { shell: "/bin/nologin".to_owned(), }, + groups: Vec::new(), } } } diff --git a/src/userlib/mod.rs b/src/userlib/mod.rs index 6e25227..4764654 100644 --- a/src/userlib/mod.rs +++ b/src/userlib/mod.rs @@ -62,11 +62,12 @@ impl UserDBLocal { let mut users = user_vec_to_hashmap(string_to(&my_passwd_lines)); let passwds: Vec = string_to(&my_shadow_lines); + let groups: Vec = string_to(&my_group_lines); shadow_to_users(&mut users, passwds); Ok(Self { source_files: files, users, - groups: string_to(&my_group_lines), + groups, source_hashes: hashes::Hashes::new(&my_passwd_lines, &my_shadow_lines, &my_group_lines), }) } @@ -282,8 +283,8 @@ impl UserDBRead for UserDBLocal { None } - fn get_all_groups(&self) -> Vec<&crate::Group> { - self.groups.iter().collect() + fn get_all_groups(&self) -> Vec { + self.groups.iter().map(std::clone::Clone::clone).collect() } fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> {