Compare commits
	
		
			No commits in common. "b8c544a8460cffe2ff4cf56dddcd5d590ec3630b" and "56a6679ccbfcd6e5341125964e924ac71ce5b295" have entirely different histories.
		
	
	
		
			b8c544a846
			...
			56a6679ccb
		
	
		
@ -7,9 +7,9 @@ fn main() {
 | 
				
			|||||||
        simplelog::TerminalMode::Mixed,
 | 
					        simplelog::TerminalMode::Mixed,
 | 
				
			||||||
    )])
 | 
					    )])
 | 
				
			||||||
    .unwrap();
 | 
					    .unwrap();
 | 
				
			||||||
    //use adduser::api::UserDBWrite;
 | 
					    use adduser::api::UserDBWrite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let _db = adduser::UserDBLocal::load_files(adduser::Files::default());
 | 
					    let mut db = adduser::UserDBLocal::load_files(adduser::Files::default());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let user = adduser::User::default()
 | 
					    let user = adduser::User::default()
 | 
				
			||||||
        .username("fest".into())
 | 
					        .username("fest".into())
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +0,0 @@
 | 
				
			|||||||
extern crate adduser;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn main() {
 | 
					 | 
				
			||||||
    simplelog::CombinedLogger::init(vec![simplelog::TermLogger::new(
 | 
					 | 
				
			||||||
        simplelog::LevelFilter::Warn,
 | 
					 | 
				
			||||||
        simplelog::Config::default(),
 | 
					 | 
				
			||||||
        simplelog::TerminalMode::Mixed,
 | 
					 | 
				
			||||||
    )])
 | 
					 | 
				
			||||||
    .unwrap();
 | 
					 | 
				
			||||||
    use adduser::api::UserDBWrite;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut db = adduser::UserDBLocal::load_files(adduser::Files::default());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let user = db.delete_user("teste").expect("failed to delete the user");
 | 
					 | 
				
			||||||
    println!("The user {} has been deleted!", user);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -123,27 +123,22 @@ impl crate::api::UserRead for User {
 | 
				
			|||||||
        Some(&self.shell_path.shell)
 | 
					        Some(&self.shell_path.shell)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    fn get_full_name(&self) -> Option<&str> {
 | 
					    fn get_full_name(&self) -> Option<&str> {
 | 
				
			||||||
        self.gecos.get_full_name()
 | 
					        self.gecos.get_full_name()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    fn get_room(&self) -> Option<&str> {
 | 
					    fn get_room(&self) -> Option<&str> {
 | 
				
			||||||
        self.gecos.get_room()
 | 
					        self.gecos.get_room()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    fn get_phone_work(&self) -> Option<&str> {
 | 
					    fn get_phone_work(&self) -> Option<&str> {
 | 
				
			||||||
        self.gecos.get_phone_work()
 | 
					        self.gecos.get_phone_work()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    fn get_phone_home(&self) -> Option<&str> {
 | 
					    fn get_phone_home(&self) -> Option<&str> {
 | 
				
			||||||
        self.gecos.get_phone_home()
 | 
					        self.gecos.get_phone_home()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					 | 
				
			||||||
    fn get_other(&self) -> Option<&Vec<String>> {
 | 
					    fn get_other(&self) -> Option<&Vec<String>> {
 | 
				
			||||||
        self.gecos.get_other()
 | 
					        self.gecos.get_other()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -205,8 +200,8 @@ impl Display for User {
 | 
				
			|||||||
fn test_default_user() {
 | 
					fn test_default_user() {
 | 
				
			||||||
    // Check if a user can be created.
 | 
					    // Check if a user can be created.
 | 
				
			||||||
    let mut pwd = User::default();
 | 
					    let mut pwd = User::default();
 | 
				
			||||||
    assert_eq!(pwd.username.username, "defaultusername");
 | 
					    assert_eq!(pwd.username.username, "defaultuser");
 | 
				
			||||||
    assert_eq!(pwd.home_dir.dir, "/");
 | 
					    assert_eq!(pwd.home_dir.dir, "/home/default");
 | 
				
			||||||
    assert_eq!(pwd.uid.uid, 1001);
 | 
					    assert_eq!(pwd.uid.uid, 1001);
 | 
				
			||||||
    let npw = pwd.username("test".to_owned()).clone();
 | 
					    let npw = pwd.username("test".to_owned()).clone();
 | 
				
			||||||
    assert_eq!(npw.username.username, "test");
 | 
					    assert_eq!(npw.username.username, "test");
 | 
				
			||||||
 | 
				
			|||||||
@ -89,9 +89,9 @@ impl TryFrom<String> for EncryptedPassword {
 | 
				
			|||||||
    type Error = UserLibError;
 | 
					    type Error = UserLibError;
 | 
				
			||||||
    fn try_from(source: String) -> std::result::Result<Self, Self::Error> {
 | 
					    fn try_from(source: String) -> std::result::Result<Self, Self::Error> {
 | 
				
			||||||
        if source == "x" {
 | 
					        if source == "x" {
 | 
				
			||||||
            //warn!("password from shadow not loaded!")
 | 
					            warn!("password from shadow not loaded!")
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            //warn!("Password field has an unexpected value")
 | 
					            warn!("Password field has an unexpected value")
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        Ok(Self { password: source })
 | 
					        Ok(Self { password: source })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										205
									
								
								src/userlib.rs
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								src/userlib.rs
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
#![warn(
 | 
					#![warn(
 | 
				
			||||||
    clippy::all,
 | 
					    clippy::all,
 | 
				
			||||||
    //clippy::restriction,
 | 
					    clippy::restriction,
 | 
				
			||||||
    clippy::pedantic,
 | 
					    clippy::pedantic,
 | 
				
			||||||
    clippy::nursery,
 | 
					    clippy::nursery,
 | 
				
			||||||
    clippy::cargo
 | 
					    clippy::cargo
 | 
				
			||||||
@ -9,11 +9,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use crate::api::GroupRead;
 | 
					use crate::api::GroupRead;
 | 
				
			||||||
use crate::api::UserRead;
 | 
					use crate::api::UserRead;
 | 
				
			||||||
use log::{debug, error, info, warn};
 | 
					use log::warn;
 | 
				
			||||||
 | 
					use std::collections::HashMap;
 | 
				
			||||||
use std::fs::File;
 | 
					use std::fs::File;
 | 
				
			||||||
use std::io::{BufReader, Read};
 | 
					use std::io::{BufReader, Read};
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::{collections::HashMap, io::Write};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct UserDBLocal {
 | 
					pub struct UserDBLocal {
 | 
				
			||||||
    source_files: Files,
 | 
					    source_files: Files,
 | 
				
			||||||
@ -38,168 +38,6 @@ impl Default for Files {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Files {
 | 
					 | 
				
			||||||
    pub fn lock_and_get_passwd(&self) -> Result<LockedFileGuard, crate::UserLibError> {
 | 
					 | 
				
			||||||
        LockedFileGuard::new(self.passwd.as_ref().unwrap())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn lock_and_get_shadow(&self) -> Result<LockedFileGuard, crate::UserLibError> {
 | 
					 | 
				
			||||||
        LockedFileGuard::new(self.shadow.as_ref().unwrap())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub fn lock_and_get_group(&self) -> Result<LockedFileGuard, crate::UserLibError> {
 | 
					 | 
				
			||||||
        LockedFileGuard::new(self.group.as_ref().unwrap())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct LockedFileGuard {
 | 
					 | 
				
			||||||
    lockfile: PathBuf,
 | 
					 | 
				
			||||||
    pub(crate) file: File,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl LockedFileGuard {
 | 
					 | 
				
			||||||
    pub fn new(path: &PathBuf) -> Result<Self, crate::userlib_error::UserLibError> {
 | 
					 | 
				
			||||||
        let locked = Self::try_to_lock_file(path);
 | 
					 | 
				
			||||||
        match locked {
 | 
					 | 
				
			||||||
            Ok((lockfile, file)) => Ok(Self { lockfile, file }),
 | 
					 | 
				
			||||||
            Err(e) => Err(e),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn try_to_lock_file(path: &PathBuf) -> Result<(PathBuf, File), crate::UserLibError> {
 | 
					 | 
				
			||||||
        // Ok write "/etc/passwd.12397" to file
 | 
					 | 
				
			||||||
        // Ok write "/etc/passwd.lock" to lock
 | 
					 | 
				
			||||||
        // Ok get the pid
 | 
					 | 
				
			||||||
        // Ok open the file
 | 
					 | 
				
			||||||
        // Ok write all to the tempfile
 | 
					 | 
				
			||||||
        // Ok try to make a link from the file created to the lockfile
 | 
					 | 
				
			||||||
        // Ok ensure that the file has been linked successfully
 | 
					 | 
				
			||||||
        // Ok Open the lockfile
 | 
					 | 
				
			||||||
        // Ok read the contents of the lockfile
 | 
					 | 
				
			||||||
        // Ok check if the lockfile contains a pid if not error out
 | 
					 | 
				
			||||||
        // Ok check if the containing pid is in a valid format. If not create a matching error
 | 
					 | 
				
			||||||
        // test if this process could be killed. If so disclose the pid in the error.
 | 
					 | 
				
			||||||
        // try to delete the lockfile as it is apparently not used by the process anmore. (cleanup)
 | 
					 | 
				
			||||||
        // try to lock again now that the old logfile has been safely removed.
 | 
					 | 
				
			||||||
        // remove the original file and only keep the lock hardlink
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        info!("locking file {}", path.to_string_lossy());
 | 
					 | 
				
			||||||
        let mut tempfilepath = path.clone();
 | 
					 | 
				
			||||||
        // get the pid
 | 
					 | 
				
			||||||
        let pid = std::process::id();
 | 
					 | 
				
			||||||
        debug!("using pid {}", std::process::id());
 | 
					 | 
				
			||||||
        // get the filename
 | 
					 | 
				
			||||||
        let filename = tempfilepath.file_name().unwrap().to_owned();
 | 
					 | 
				
			||||||
        // and the base path which is the base for tempfile and lockfile.
 | 
					 | 
				
			||||||
        tempfilepath.pop();
 | 
					 | 
				
			||||||
        let mut lockfilepath = tempfilepath.clone();
 | 
					 | 
				
			||||||
        // push the filenames to the paths
 | 
					 | 
				
			||||||
        tempfilepath.push(format!("{}.{}", filename.to_str().unwrap(), pid));
 | 
					 | 
				
			||||||
        lockfilepath.push(format!("{}.lock", filename.to_str().unwrap()));
 | 
					 | 
				
			||||||
        debug!(
 | 
					 | 
				
			||||||
            "Lockfile paths: {:?} (temporary) {:?} (final)",
 | 
					 | 
				
			||||||
            tempfilepath, lockfilepath
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        // write the pid into the tempfile
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            let mut tempfile = File::create(&tempfilepath)
 | 
					 | 
				
			||||||
                .expect(&format!("Failed to open {}", filename.to_str().unwrap()));
 | 
					 | 
				
			||||||
            match write!(tempfile, "{}", pid) {
 | 
					 | 
				
			||||||
                Ok(_) => {}
 | 
					 | 
				
			||||||
                Err(_) => {
 | 
					 | 
				
			||||||
                    let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                    error!("could not write to {}", filename.to_string_lossy())
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // try to make a hardlink from the lockfile to the tempfile
 | 
					 | 
				
			||||||
        let linkresult = std::fs::hard_link(&tempfilepath, &lockfilepath);
 | 
					 | 
				
			||||||
        match linkresult {
 | 
					 | 
				
			||||||
            Ok(()) => {
 | 
					 | 
				
			||||||
                debug!("successfully locked");
 | 
					 | 
				
			||||||
                let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // open the file
 | 
					 | 
				
			||||||
                let resfile = File::open(&path);
 | 
					 | 
				
			||||||
                return match resfile {
 | 
					 | 
				
			||||||
                    Ok(file) => Ok((lockfilepath, file)),
 | 
					 | 
				
			||||||
                    Err(e) => {
 | 
					 | 
				
			||||||
                        // failed to open the file undo the locks
 | 
					 | 
				
			||||||
                        let _ = std::fs::remove_file(&lockfilepath);
 | 
					 | 
				
			||||||
                        let ret: crate::UserLibError = format!(
 | 
					 | 
				
			||||||
                            "Failed to open the file: {}, error: {}",
 | 
					 | 
				
			||||||
                            path.to_str().unwrap(),
 | 
					 | 
				
			||||||
                            e
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                        .into();
 | 
					 | 
				
			||||||
                        Err(ret)
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            Err(e) => match e.kind() {
 | 
					 | 
				
			||||||
                // analyze the error further
 | 
					 | 
				
			||||||
                std::io::ErrorKind::AlreadyExists => {
 | 
					 | 
				
			||||||
                    warn!("The file is already locked by another process! – testing the validity of the lock");
 | 
					 | 
				
			||||||
                    {
 | 
					 | 
				
			||||||
                        let mut lf = match File::open(&lockfilepath) {
 | 
					 | 
				
			||||||
                            Ok(file) => file,
 | 
					 | 
				
			||||||
                            Err(e) => {
 | 
					 | 
				
			||||||
                                let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                                panic!("failed to open the lockfile: {}", e);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        };
 | 
					 | 
				
			||||||
                        let mut content = String::new();
 | 
					 | 
				
			||||||
                        match lf.read_to_string(&mut content) {
 | 
					 | 
				
			||||||
                            Ok(_) => {}
 | 
					 | 
				
			||||||
                            Err(_) => {
 | 
					 | 
				
			||||||
                                let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                                panic!("failed to read the lockfile{}", e);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        let content = content.trim().trim_matches(char::from(0));
 | 
					 | 
				
			||||||
                        let lock_pid = content.parse::<u32>();
 | 
					 | 
				
			||||||
                        match lock_pid {
 | 
					 | 
				
			||||||
                            Ok(pid) => {
 | 
					 | 
				
			||||||
                                warn!(
 | 
					 | 
				
			||||||
                                    "found a pid: {}, checking if this process is still running",
 | 
					 | 
				
			||||||
                                    pid
 | 
					 | 
				
			||||||
                                );
 | 
					 | 
				
			||||||
                                error!("The file could not be locked");
 | 
					 | 
				
			||||||
                                let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                                todo!("Validate the lock and delete the file if the process does not exist anymore");
 | 
					 | 
				
			||||||
                                /*let sent = nix::sys::signal::kill(
 | 
					 | 
				
			||||||
                                    nix::unistd::Pid::from_raw(pid as i32),
 | 
					 | 
				
			||||||
                                    nix::sys::signal::Signal::from(0),
 | 
					 | 
				
			||||||
                                );*/
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            Err(e) => {
 | 
					 | 
				
			||||||
                                let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                                error!(
 | 
					 | 
				
			||||||
                                    "existing lock file {} with an invalid PID '{}' Error: {}",
 | 
					 | 
				
			||||||
                                    lockfilepath.to_str().unwrap(),
 | 
					 | 
				
			||||||
                                    content,
 | 
					 | 
				
			||||||
                                    e
 | 
					 | 
				
			||||||
                                )
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                _ => {
 | 
					 | 
				
			||||||
                    let _ = std::fs::remove_file(&tempfilepath);
 | 
					 | 
				
			||||||
                    panic!("failed to lock the file: {}", e);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Err("was not able to lock!".into())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Drop for LockedFileGuard {
 | 
					 | 
				
			||||||
    fn drop(&mut self) {
 | 
					 | 
				
			||||||
        info!("removing lock");
 | 
					 | 
				
			||||||
        std::fs::remove_file(&self.lockfile).unwrap();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl UserDBLocal {
 | 
					impl UserDBLocal {
 | 
				
			||||||
    /// Import the database from strings
 | 
					    /// Import the database from strings
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
@ -227,20 +65,9 @@ impl UserDBLocal {
 | 
				
			|||||||
    /// Import the database from a [`Files`] struct
 | 
					    /// Import the database from a [`Files`] struct
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn load_files(files: Files) -> Self {
 | 
					    pub fn load_files(files: Files) -> Self {
 | 
				
			||||||
        // Get the Strings for the files use an inner block to drop references after read.
 | 
					        let my_passwd_lines = file_to_string(files.passwd.as_ref());
 | 
				
			||||||
        let (my_passwd_lines, my_shadow_lines, my_group_lines) = {
 | 
					        let my_group_lines = file_to_string(files.group.as_ref());
 | 
				
			||||||
            let locked_p = files.lock_and_get_passwd();
 | 
					        let my_shadow_lines = file_to_string(files.shadow.as_ref());
 | 
				
			||||||
            let locked_s = files.lock_and_get_shadow();
 | 
					 | 
				
			||||||
            let locked_g = files.lock_and_get_group();
 | 
					 | 
				
			||||||
            use std::{thread, time};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            let ten_millis = time::Duration::from_millis(10000);
 | 
					 | 
				
			||||||
            thread::sleep(ten_millis);
 | 
					 | 
				
			||||||
            let p = file_to_string(&locked_p.unwrap().file);
 | 
					 | 
				
			||||||
            let s = file_to_string(&locked_s.unwrap().file);
 | 
					 | 
				
			||||||
            let g = file_to_string(&locked_g.unwrap().file);
 | 
					 | 
				
			||||||
            (p, s, g)
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut users = user_vec_to_hashmap(string_to(&my_passwd_lines));
 | 
					        let mut users = user_vec_to_hashmap(string_to(&my_passwd_lines));
 | 
				
			||||||
        let passwds: Vec<crate::Shadow> = string_to(&my_shadow_lines);
 | 
					        let passwds: Vec<crate::Shadow> = string_to(&my_shadow_lines);
 | 
				
			||||||
@ -306,7 +133,7 @@ impl UserDBWrite for UserDBLocal {
 | 
				
			|||||||
        todo!()
 | 
					        todo!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn delete_group(&mut self, _group: &crate::Group) -> Result<(), crate::UserLibError> {
 | 
					    fn delete_group(&mut self, group: &crate::Group) -> Result<(), crate::UserLibError> {
 | 
				
			||||||
        todo!()
 | 
					        todo!()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -389,7 +216,7 @@ impl UserDBValidation for UserDBLocal {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn get_nth_line(path: &File, n: u32) -> String {
 | 
					fn get_nth_line(path: Option<&PathBuf>, n: u32) -> String {
 | 
				
			||||||
    let lines = file_to_string(path);
 | 
					    let lines = file_to_string(path);
 | 
				
			||||||
    let line = lines.lines().nth(n as usize);
 | 
					    let line = lines.lines().nth(n as usize);
 | 
				
			||||||
    match line {
 | 
					    match line {
 | 
				
			||||||
@ -399,7 +226,9 @@ fn get_nth_line(path: &File, n: u32) -> String {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Parse a file to a string
 | 
					/// Parse a file to a string
 | 
				
			||||||
fn file_to_string(file: &File) -> String {
 | 
					fn file_to_string(path: Option<&PathBuf>) -> String {
 | 
				
			||||||
 | 
					    let file = File::open(path.expect("Path cannot be None".into()))
 | 
				
			||||||
 | 
					        .expect("Failed to read the file. Most of the time root permissions are needed".into());
 | 
				
			||||||
    let mut reader = BufReader::new(file);
 | 
					    let mut reader = BufReader::new(file);
 | 
				
			||||||
    let mut lines = String::new();
 | 
					    let mut lines = String::new();
 | 
				
			||||||
    reader.read_to_string(&mut lines).unwrap();
 | 
					    reader.read_to_string(&mut lines).unwrap();
 | 
				
			||||||
@ -475,20 +304,16 @@ fn test_creator_user_db_local() {
 | 
				
			|||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_parsing_local_database() {
 | 
					fn test_parsing_local_database() {
 | 
				
			||||||
    // Parse the worldreadable user database ignore the shadow database as this would require root privileges.
 | 
					    // Parse the worldreadable user database ignore the shadow database as this would require root privileges.
 | 
				
			||||||
    let pwdfile = File::open(PathBuf::from("/etc/passwd")).unwrap();
 | 
					    let my_passwd_lines = file_to_string(Some(&PathBuf::from("/etc/passwd")));
 | 
				
			||||||
    let grpfile = File::open(PathBuf::from("/etc/group")).unwrap();
 | 
					    let my_group_lines = file_to_string(Some(&PathBuf::from("/etc/group")));
 | 
				
			||||||
    let my_passwd_lines = file_to_string(&pwdfile);
 | 
					 | 
				
			||||||
    let my_group_lines = file_to_string(&grpfile);
 | 
					 | 
				
			||||||
    let data = UserDBLocal::import_from_strings(&my_passwd_lines, "", &my_group_lines);
 | 
					    let data = UserDBLocal::import_from_strings(&my_passwd_lines, "", &my_group_lines);
 | 
				
			||||||
    assert_eq!(data.groups.get(0).unwrap().get_groupname().unwrap(), "root");
 | 
					    assert_eq!(data.groups.get(0).unwrap().get_groupname().unwrap(), "root");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[test]
 | 
					#[test]
 | 
				
			||||||
fn test_user_db_read_implementation() {
 | 
					fn test_user_db_read_implementation() {
 | 
				
			||||||
    let pwdfile = File::open(PathBuf::from("/etc/passwd")).unwrap();
 | 
					    let pass = file_to_string(Some(&PathBuf::from("/etc/passwd")));
 | 
				
			||||||
    let grpfile = File::open(PathBuf::from("/etc/group")).unwrap();
 | 
					    let group = file_to_string(Some(&PathBuf::from("/etc/group")));
 | 
				
			||||||
    let pass = file_to_string(&pwdfile);
 | 
					 | 
				
			||||||
    let group = file_to_string(&grpfile);
 | 
					 | 
				
			||||||
    let data = UserDBLocal::import_from_strings(&pass, "", &group);
 | 
					    let data = UserDBLocal::import_from_strings(&pass, "", &group);
 | 
				
			||||||
    // Usually there are more than 10 users
 | 
					    // Usually there are more than 10 users
 | 
				
			||||||
    assert!(data.get_all_users().len() > 10);
 | 
					    assert!(data.get_all_users().len() > 10);
 | 
				
			||||||
 | 
				
			|||||||
@ -23,12 +23,9 @@ pub enum UserLibError {
 | 
				
			|||||||
impl Display for UserLibError {
 | 
					impl Display for UserLibError {
 | 
				
			||||||
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
					    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Self::NotFound => write!(f, "not found"),
 | 
					            Self::NotFound => write!(f, "{}", self.to_string()),
 | 
				
			||||||
            Self::ParseError => write!(f, "failed to parse"),
 | 
					            Self::ParseError => write!(f, "{}", self.to_string()),
 | 
				
			||||||
            Self::FilesChanged => write!(
 | 
					            Self::FilesChanged => write!(f, "{}", self.to_string()),
 | 
				
			||||||
                f,
 | 
					 | 
				
			||||||
                "The files changed. Updating could lead to conflict aborting."
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            Self::Message(message) => write!(f, "{}", message),
 | 
					            Self::Message(message) => write!(f, "{}", message),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -36,7 +33,12 @@ impl Display for UserLibError {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
impl Error for UserLibError {
 | 
					impl Error for UserLibError {
 | 
				
			||||||
    fn description(&self) -> &str {
 | 
					    fn description(&self) -> &str {
 | 
				
			||||||
        todo!()
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::NotFound => "not found",
 | 
				
			||||||
 | 
					            Self::ParseError => "failed to parse",
 | 
				
			||||||
 | 
					            Self::FilesChanged => "The files changed. Updating could lead to conflict aborting.",
 | 
				
			||||||
 | 
					            Self::Message(message) => message,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user