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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user