From 403f948c67a192dea33831e8cb2583d997699cc0 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 18 Oct 2020 15:22:17 +0200 Subject: [PATCH] implement `UserDbRead` --- src/api.rs | 26 ++++++------ src/group/mod.rs | 4 ++ src/user/passwd_fields.rs | 4 ++ src/userlib.rs | 83 ++++++++++++++++++++++++++++++++------- 4 files changed, 89 insertions(+), 28 deletions(-) diff --git a/src/api.rs b/src/api.rs index 1914170..e2793a8 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,27 +1,27 @@ -trait UserDBRead { - fn get_all_users(&self) -> Vec; - fn get_user_by_name(&self, name: &str) -> Option; - fn get_user_by_id(&self, uid: u64) -> Option; - fn get_all_groups(&self) -> Vec; - fn get_group_by_name(&self) -> Option; - fn get_group_by_id(&self) -> Option; +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_group_by_name(&self, name: &str) -> Option<&crate::Group>; + fn get_group_by_id(&self, name: u32) -> Option<&crate::Group>; } -trait UserDBValidation { +pub trait UserDBValidation { fn is_uid_valid_and_free(&self) -> bool; fn is_username_valid_and_free(&self) -> bool; fn is_gid_valid_and_free(&self) -> bool; fn is_groupname_valid_and_free(&self) -> bool; } -trait UserDBWrite { +pub trait UserDBWrite { fn delete_user(&self) -> Option; fn new_user(&self) -> Option; fn delete_group(&self) -> Option; fn new_group(&self) -> Option; } -trait UserRead { +pub trait UserRead { fn get_username(&self) -> Option; fn get_uid(&self) -> Option; fn get_gid(&self) -> Option; @@ -36,7 +36,7 @@ trait UserRead { fn get_other(&self) -> Option>; } -trait UserWrite { +pub trait UserWrite { fn set_username(&self) -> Option; fn set_uid(&self) -> Option; fn set_gid(&self) -> Option; @@ -51,14 +51,14 @@ trait UserWrite { fn set_other(&self) -> Option>; } -trait GroupRead { +pub trait GroupRead { fn get_groupname(&self) -> Option; fn get_encrypted_password(&self) -> Option; fn get_gid(&self) -> Option; fn get_members(&self) -> Option; } -trait GroupWrite { +pub trait GroupWrite { fn set_groupname(&self) -> Option; fn set_password(&self) -> Option; fn set_gid(&self) -> Option; diff --git a/src/group/mod.rs b/src/group/mod.rs index 90e6725..0dc3ddf 100644 --- a/src/group/mod.rs +++ b/src/group/mod.rs @@ -66,6 +66,10 @@ impl Group { pub const fn get_members(&self) -> &Vec { &self.members } + + pub fn get_gid(&self) -> u32 { + self.gid.get_gid() + } } impl Display for Group { diff --git a/src/user/passwd_fields.rs b/src/user/passwd_fields.rs index 3e67e8c..1ccdbcb 100644 --- a/src/user/passwd_fields.rs +++ b/src/user/passwd_fields.rs @@ -147,6 +147,10 @@ impl Gid { // since it is a u32 it cannot be smaller than 0 self.gid < 1000 } + + pub const fn get_gid(&self) -> u32 { + self.gid + } } /// The home directory of a user diff --git a/src/userlib.rs b/src/userlib.rs index 3e411a5..7ec2ea7 100644 --- a/src/userlib.rs +++ b/src/userlib.rs @@ -16,7 +16,7 @@ use std::path::PathBuf; pub struct UserDBLocal { source_files: Files, pub users: HashMap, - pub group_entries: Vec, + pub groups: Vec, } pub struct Files { @@ -55,7 +55,7 @@ impl UserDBLocal { shadow: None, }, users, - group_entries: groups, + groups, }; res } @@ -73,10 +73,52 @@ impl UserDBLocal { Self { source_files: files, users, - group_entries: string_to(&my_group_lines), + groups: string_to(&my_group_lines), } } } +use crate::api::UserDBRead; +impl UserDBRead for UserDBLocal { + fn get_all_users(&self) -> Vec<&crate::User> { + self.users.iter().map(|(_, x)| x).collect() + } + + fn get_user_by_name(&self, name: &str) -> Option<&crate::User> { + self.users.get(name) + } + + fn get_user_by_id(&self, uid: u32) -> Option<&crate::User> { + // could probably be more efficient - on the other hand its no problem to loop a thousand users. + for (_, user) in self.users.iter() { + if user.get_uid() == uid { + return Some(&user); + } + } + None + } + + fn get_all_groups(&self) -> Vec<&crate::Group> { + self.groups.iter().collect() + } + + fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> { + for group in self.groups.iter() { + if group.get_groupname() == name { + return Some(group); + } + } + None + } + + fn get_group_by_id(&self, id: u32) -> Option<&crate::Group> { + for group in self.groups.iter() { + if group.get_gid() == id { + return Some(group); + } + } + None + } +} /// Parse a file to a string fn file_to_string(path: Option<&PathBuf>) -> String { @@ -129,7 +171,7 @@ where .lines() .filter_map(|line| { if line.len() > 5 { - println!("{}", line); + //println!("{}", line); Some(T::new_from_string(line.to_owned()).expect("failed to read lines")) } else { None @@ -146,16 +188,27 @@ fn test_creator_user_db_local() { #[test] fn test_parsing_local_database() { - use std::fs::File; - use std::io::{BufReader, Read}; - let passwd_file = File::open("/etc/passwd").unwrap(); - let mut passwd_reader = BufReader::new(passwd_file); - let mut my_passwd_lines = "".to_string(); - passwd_reader.read_to_string(&mut my_passwd_lines).unwrap(); - let group_file = File::open("/etc/group").unwrap(); - let mut group_reader = BufReader::new(group_file); - let mut my_group_lines = "".to_string(); - group_reader.read_to_string(&mut my_group_lines).unwrap(); + // Parse the worldreadable user database ignore the shadow database as this would require root privileges. + let my_passwd_lines = file_to_string(Some(&PathBuf::from("/etc/passwd"))); + let my_group_lines = file_to_string(Some(&PathBuf::from("/etc/group"))); let data = UserDBLocal::import_from_strings(&my_passwd_lines, "", &my_group_lines); - assert_eq!(data.group_entries.get(0).unwrap().get_groupname(), "root"); + assert_eq!(data.groups.get(0).unwrap().get_groupname(), "root"); +} + +#[test] +fn test_user_db_read_implementation() { + let pass = file_to_string(Some(&PathBuf::from("/etc/passwd"))); + let group = file_to_string(Some(&PathBuf::from("/etc/group"))); + let data = UserDBLocal::import_from_strings(&pass, "", &group); + // Usually there are more than 10 users + assert!(data.get_all_users().len() > 10); + assert!(data.get_user_by_name("root").is_some()); + assert_eq!(data.get_user_by_name("root").unwrap().get_uid(), 0); + assert_eq!(data.get_user_by_id(0).unwrap().get_username(), "root"); + assert!(data.get_all_groups().len() > 10); + assert!(data.get_group_by_name("root").is_some()); + assert_eq!(data.get_group_by_name("root").unwrap().get_gid(), 0); + assert_eq!(data.get_group_by_id(0).unwrap().get_groupname(), "root"); + assert!(data.get_user_by_name("norealnameforsure").is_none()); + assert!(data.get_group_by_name("norealgroupforsure").is_none()); }