make userlib module a directory

This commit is contained in:
Dietrich 2020-10-30 16:13:05 +01:00
parent 1af8a7cd65
commit 8337c737d9
5 changed files with 69 additions and 40 deletions

View File

@ -17,6 +17,7 @@ pub enum UserLibError {
NotFound, NotFound,
ParseError, ParseError,
FilesChanged, FilesChanged,
FilesRequired,
Message(MyMessage), Message(MyMessage),
} }
@ -46,6 +47,10 @@ impl Display for UserLibError {
match self { match self {
Self::NotFound => write!(f, "not found"), Self::NotFound => write!(f, "not found"),
Self::ParseError => write!(f, "failed to parse"), Self::ParseError => write!(f, "failed to parse"),
UserLibError::FilesRequired => write!(
f,
"File locking is only possible if some files are specified"
),
Self::FilesChanged => write!( Self::FilesChanged => write!(
f, f,
"The files changed. Updating could lead to conflict aborting." "The files changed. Updating could lead to conflict aborting."
@ -58,7 +63,10 @@ impl Display for UserLibError {
impl Error for UserLibError { impl Error for UserLibError {
fn source(&self) -> Option<&(dyn Error + 'static)> { fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self { match *self {
UserLibError::NotFound | UserLibError::ParseError | UserLibError::FilesChanged => None, UserLibError::NotFound
| UserLibError::ParseError
| UserLibError::FilesChanged
| UserLibError::FilesRequired => None,
UserLibError::Message(MyMessage::IOError(_, ref e)) => Some(e), UserLibError::Message(MyMessage::IOError(_, ref e)) => Some(e),
UserLibError::Message(MyMessage::Simple(_)) => None, UserLibError::Message(MyMessage::Simple(_)) => None,
} }

View File

@ -10,7 +10,7 @@
use crate::userlib::NewFromString; use crate::userlib::NewFromString;
use log::warn; use log::warn;
use crate::userlib_error::UserLibError; use crate::UserLibError;
use std::cmp::Eq; use std::cmp::Eq;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};

View File

@ -4,10 +4,11 @@ extern crate lazy_static;
extern crate log; extern crate log;
pub mod api; pub mod api;
pub mod error;
pub mod group; pub mod group;
pub mod user; pub mod user;
pub mod userlib; pub mod userlib;
pub mod userlib_error; pub use error::UserLibError;
pub use group::Group; pub use group::Group;
pub use user::gecos_fields::Gecos; pub use user::gecos_fields::Gecos;
pub use user::passwd_fields::{ pub use user::passwd_fields::{
@ -16,4 +17,3 @@ pub use user::passwd_fields::{
pub use user::shadow_fields::Shadow; pub use user::shadow_fields::Shadow;
pub use user::User; pub use user::User;
pub use userlib::{Files, NewFromString, UserDBLocal}; pub use userlib::{Files, NewFromString, UserDBLocal};
pub use userlib_error::UserLibError;

View File

@ -10,7 +10,7 @@
use crate::userlib::NewFromString; use crate::userlib::NewFromString;
use log::warn; use log::warn;
use crate::userlib_error::UserLibError; use crate::UserLibError;
use std::cmp::Eq; use std::cmp::Eq;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{self, Debug, Display}; use std::fmt::{self, Debug, Display};

View File

@ -41,14 +41,30 @@ impl Default for Files {
} }
impl Files { impl Files {
/// Check if all the files are defined. Because some operations require the files to be present
pub fn is_virtual(&self) -> bool {
!(self.group.is_some() & self.passwd.is_some() & self.shadow.is_some())
}
pub fn lock_and_get_passwd(&self) -> Result<LockedFileGuard, crate::UserLibError> { pub fn lock_and_get_passwd(&self) -> Result<LockedFileGuard, crate::UserLibError> {
LockedFileGuard::new(self.passwd.as_ref().unwrap()) let path = self.passwd.as_ref();
match path {
Some(p) => LockedFileGuard::new(p),
None => Err(crate::UserLibError::FilesRequired),
}
} }
pub fn lock_and_get_shadow(&self) -> Result<LockedFileGuard, crate::UserLibError> { pub fn lock_and_get_shadow(&self) -> Result<LockedFileGuard, crate::UserLibError> {
LockedFileGuard::new(self.shadow.as_ref().unwrap()) let path = self.shadow.as_ref();
match path {
Some(p) => LockedFileGuard::new(p),
None => Err(crate::UserLibError::FilesRequired),
}
} }
pub fn lock_and_get_group(&self) -> Result<LockedFileGuard, crate::UserLibError> { pub fn lock_and_get_group(&self) -> Result<LockedFileGuard, crate::UserLibError> {
LockedFileGuard::new(self.group.as_ref().unwrap()) let path = self.group.as_ref();
match path {
Some(p) => LockedFileGuard::new(p),
None => Err(crate::UserLibError::FilesRequired),
}
} }
pub fn lock_all_get( pub fn lock_all_get(
@ -68,7 +84,7 @@ pub struct LockedFileGuard {
} }
impl LockedFileGuard { impl LockedFileGuard {
pub fn new(path: &PathBuf) -> Result<Self, crate::userlib_error::UserLibError> { pub fn new(path: &PathBuf) -> Result<Self, crate::UserLibError> {
let locked = Self::try_to_lock_file(path); let locked = Self::try_to_lock_file(path);
match locked { match locked {
Ok((lockfile, file)) => Ok(Self { Ok((lockfile, file)) => Ok(Self {
@ -80,10 +96,7 @@ impl LockedFileGuard {
} }
} }
pub fn replace_contents( pub fn replace_contents(&mut self, new_content: String) -> Result<(), crate::UserLibError> {
&mut self,
new_content: String,
) -> Result<(), crate::userlib_error::UserLibError> {
self.file = File::create(&self.path).expect("Failed to truncate file."); self.file = File::create(&self.path).expect("Failed to truncate file.");
self.file self.file
.write_all(&new_content.into_bytes()) .write_all(&new_content.into_bytes())
@ -298,9 +311,6 @@ impl UserDBLocal {
use crate::api::UserDBWrite; use crate::api::UserDBWrite;
impl UserDBWrite for UserDBLocal { impl UserDBWrite for UserDBLocal {
fn delete_user(&mut self, username: &str) -> Result<crate::User, crate::UserLibError> { fn delete_user(&mut self, username: &str) -> Result<crate::User, crate::UserLibError> {
let opened = self.source_files.lock_all_get();
let (mut locked_p, locked_s, locked_g) = opened.expect("failed to lock files!");
// try to get the user from the database // try to get the user from the database
let user_opt = self.users.get(username); let user_opt = self.users.get(username);
let user = match user_opt { let user = match user_opt {
@ -310,30 +320,43 @@ impl UserDBWrite for UserDBLocal {
} }
}; };
// read the files to strings if self.source_files.is_virtual() {
let p = file_to_string(&locked_p.file)?; warn!("There are no associated files working in dummy mode!");
let _s = file_to_string(&locked_s.file)?; let res = self.users.remove(username);
let _g = file_to_string(&locked_g.file)?; match res {
{ Some(u) => Ok(u),
if self.source_hashes.passwd.has_changed(&p) { None => Err(crate::UserLibError::NotFound),
error!("The source files have changed. Deleting the user could corrupt the userdatabase. Aborting!"); }
} else { } else {
// create the new content of passwd let opened = self.source_files.lock_all_get();
let modified = user.remove_in(&p); let (mut locked_p, locked_s, locked_g) = opened.expect("failed to lock files!");
// write the new content to the file.
let ncont = locked_p.replace_contents(modified); // read the files to strings
match ncont { let p = file_to_string(&locked_p.file)?;
Ok(_) => { let _s = file_to_string(&locked_s.file)?;
return Ok(user.clone()); let _g = file_to_string(&locked_g.file)?;
} {
Err(_) => { if self.source_hashes.passwd.has_changed(&p) {
return Err("Error during write to the database. \ error!("The source files have changed. Deleting the user could corrupt the userdatabase. Aborting!");
} else {
// create the new content of passwd
let modified = user.remove_in(&p);
// write the new content to the file.
let ncont = locked_p.replace_contents(modified);
match ncont {
Ok(_) => {
let res = self.users.remove(username);
return Ok(res.unwrap());
}
Err(_) => {
return Err("Error during write to the database. \
Please doublecheck as the userdatabase could be corrupted: {}" Please doublecheck as the userdatabase could be corrupted: {}"
.into()); .into());
}
} }
} }
Err(format!("The user has been changed {}", username).into())
} }
Err(format!("The user has been changed {}", username).into())
} }
} }
@ -417,7 +440,7 @@ impl UserDBRead for UserDBLocal {
fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> { fn get_group_by_name(&self, name: &str) -> Option<&crate::Group> {
for group in self.groups.iter() { for group in self.groups.iter() {
if group.get_groupname().unwrap() == name { if group.get_groupname()? == name {
return Some(group); return Some(group);
} }
} }
@ -426,7 +449,7 @@ impl UserDBRead for UserDBLocal {
fn get_group_by_id(&self, id: u32) -> Option<&crate::Group> { fn get_group_by_id(&self, id: u32) -> Option<&crate::Group> {
for group in self.groups.iter() { for group in self.groups.iter() {
if group.get_gid().unwrap() == id { if group.get_gid()? == id {
return Some(group); return Some(group);
} }
} }
@ -618,7 +641,6 @@ fn test_user_db_read_implementation() {
#[test] #[test]
fn test_user_db_write_implementation() { fn test_user_db_write_implementation() {
/* only works on files now
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$/RotIe4VZzzAun4W$7YUONvru1rDnllN5TvrnOMsWUD5wSDUPAD6t6/Xwsr/0QOuWF3HcfAhypRkGa8G1B9qqWV5kZSnCb8GKMN9N61:18260:0:99999:7:::", "teste:x:1002:test,test");
let user = "test"; let user = "test";
@ -626,5 +648,4 @@ fn test_user_db_write_implementation() {
assert!(data.delete_user(&user).is_ok()); assert!(data.delete_user(&user).is_ok());
assert!(data.delete_user(&user).is_err()); assert!(data.delete_user(&user).is_err());
assert_eq!(data.get_all_users().len(), 0); assert_eq!(data.get_all_users().len(), 0);
*/
} }