Compare commits

...

5 Commits

8 changed files with 111 additions and 42 deletions

View File

@ -17,18 +17,18 @@ pub trait UserDBValidation {
pub trait UserDBWrite {
fn delete_user(&mut self, user: &str) -> Result<crate::User, crate::UserLibError>;
fn new_user(
&mut self,
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,
&mut self, /*
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,*/
) -> Result<&crate::User, crate::UserLibError>;
fn delete_group(&mut self, group: &crate::Group) -> Result<(), crate::UserLibError>;
fn new_group(&mut self) -> Result<&crate::Group, crate::UserLibError>;

22
src/bin/create_user.rs Normal file
View File

@ -0,0 +1,22 @@
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 = adduser::User::default()
.username("fest".into())
.shell_path("/bin/mash".into())
.clone();
println!("{}", user);
//db.new_user().expect("failed to create the user");
}

View File

@ -51,6 +51,8 @@ pub(crate) fn is_groupname_valid(name: &str) -> bool {
/// A record(line) in the user database `/etc/shadow` found in most linux systems.
#[derive(Debug, PartialEq, Eq)]
pub struct Group {
pos: u32,
source: String,
groupname: Groupname, /* Username. */
pub(crate) password: crate::Password, /* Usually not used (disabled with x) */
gid: crate::Gid, /* Group ID. */
@ -118,6 +120,8 @@ impl NewFromString for Group {
let elements: Vec<String> = line.split(':').map(ToString::to_string).collect();
if elements.len() == 4 {
Ok(Self {
pos: position,
source: line.clone(),
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())?,

View File

@ -8,7 +8,7 @@ use std::fmt::{self, Display};
/// The first 4 values are more or less standardised to be full name, room, phone at work and phone at home. After that there can be some extra fields often containing the emailadress and even additional information.
///
/// This enum represents the first 4 values by name and adds the other values to a list of strings [`Gecos::Detail`]. If only one field is found and no `,` at all this value is used as a human readable comment [`Gecos::Simple`].
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Gecos {
Detail {
full_name: String,

View File

@ -1,4 +1,5 @@
pub mod gecos_fields;
pub mod passwd_fields;
pub mod shadow_fields;
@ -7,7 +8,7 @@ use std::convert::TryFrom;
use std::fmt::{self, Display};
/// A record(line) in the user database `/etc/passwd` found in most linux systems.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct User {
source: String,
pos: u32,
@ -20,6 +21,35 @@ pub struct User {
shell_path: crate::ShellPath, /* Shell program. */
}
impl User {
pub fn username(&mut self, name: String) -> &mut Self {
self.username = crate::Username {
username: name.into(),
};
self
}
pub fn disable_password(&mut self) -> &mut Self {
self.password = crate::Password::Disabled;
self
}
pub fn uid(&mut self, uid: u32) -> &mut Self {
self.uid = crate::Uid { uid };
self
}
pub fn gid(&mut self, gid: u32) -> &mut Self {
self.gid = crate::Gid { gid };
self
}
pub fn home_dir(&mut self, path: String) -> &mut Self {
self.home_dir = crate::HomeDir { dir: path };
self
}
pub fn shell_path(&mut self, path: String) -> &mut Self {
self.shell_path = crate::ShellPath { shell: path };
self
}
}
impl NewFromString for User {
/// Parse a line formatted like one in `/etc/passwd` and construct a matching [`User`] instance
///
@ -132,21 +162,19 @@ impl Default for User {
source: "".to_owned(),
pos: u32::MAX,
username: crate::Username {
username: "defaultuser".to_owned(),
username: "defaultusername".to_owned(),
},
password: crate::Password::Encrypted(crate::EncryptedPassword {
password: "notencrypted".to_owned(),
}),
password: crate::Password::Disabled,
uid: crate::Uid { uid: 1001 },
gid: crate::Gid { gid: 1001 },
gecos: crate::Gecos::Simple {
comment: "gecos default comment".to_string(),
comment: "".to_string(),
},
home_dir: crate::HomeDir {
dir: "/home/default".to_owned(),
dir: "/".to_owned(),
},
shell_path: crate::ShellPath {
shell: "/bin/bash".to_owned(),
shell: "/bin/nologin".to_owned(),
},
}
}
@ -171,10 +199,12 @@ impl Display for User {
#[test]
fn test_default_user() {
// Check if a user can be created.
let pwd = User::default();
let mut pwd = User::default();
assert_eq!(pwd.username.username, "defaultuser");
assert_eq!(pwd.home_dir.dir, "/home/default");
assert_eq!(pwd.uid.uid, 1001);
let npw = pwd.username("test".to_owned()).clone();
assert_eq!(npw.username.username, "test");
}
#[test]

View File

@ -20,7 +20,7 @@ use std::fmt::{self, Display};
/// When done the validity will automatically be checked in the `trait TryFrom`.
///
/// In the future some extra fields might be added.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Username {
/// The username value
pub(crate) username: String,
@ -57,7 +57,7 @@ pub(crate) fn is_username_valid(name: &str) -> bool {
USERVALIDATION.is_match(name)
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Password {
Encrypted(crate::EncryptedPassword),
Shadow(crate::Shadow),
@ -74,7 +74,7 @@ impl Display for Password {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct EncryptedPassword {
pub(in crate::user) password: String,
}
@ -97,7 +97,7 @@ impl TryFrom<String> for EncryptedPassword {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Uid {
pub(in crate::user) uid: u32,
}
@ -125,7 +125,7 @@ impl Uid {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Gid {
pub(in crate::user) gid: u32,
}
@ -158,7 +158,7 @@ impl Gid {
}
/// The home directory of a user
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct HomeDir {
pub(in crate::user) dir: String,
}
@ -177,7 +177,7 @@ impl TryFrom<String> for HomeDir {
}
/// The path to the Shell binary
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ShellPath {
pub(in crate::user) shell: String,
}

View File

@ -16,8 +16,10 @@ use std::convert::TryFrom;
use std::fmt::{self, Debug, Display};
/// A record(line) in the user database `/etc/shadow` found in most linux systems.
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Shadow {
pos: u32,
source: String,
username: crate::Username, /* Username. */
pub(crate) password: crate::EncryptedPassword, /* Hashed passphrase */
last_change: Option<chrono::NaiveDateTime>, /* User ID. */
@ -98,6 +100,8 @@ impl NewFromString for Shadow {
if elements.len() == 9 {
let extra = elements.get(8).unwrap();
Ok(Self {
pos: position,
source: line.clone(),
username: crate::Username::try_from(elements.get(0).unwrap().to_string())?,
password: crate::EncryptedPassword::try_from(elements.get(1).unwrap().to_string())?,
last_change: date_since_epoch(elements.get(2).unwrap()),

View File

@ -91,18 +91,18 @@ impl UserDBWrite for UserDBLocal {
}
fn new_user(
&mut self,
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,
&mut self, /*
username: String,
enc_password: String,
uid: u32,
gid: u32,
full_name: String,
room: String,
phone_work: String,
phone_home: String,
other: Option<Vec<String>>,
home_dir: String,
shell_path: String,*/
) -> Result<&crate::User, crate::UserLibError> {
/*if self.users.contains_key(&username) {
Err(format!(
@ -216,6 +216,15 @@ impl UserDBValidation for UserDBLocal {
}
}
fn get_nth_line(path: Option<&PathBuf>, n: u32) -> String {
let lines = file_to_string(path);
let line = lines.lines().nth(n as usize);
match line {
Some(line) => line.to_owned(),
None => "".to_owned(),
}
}
/// Parse a file to a string
fn file_to_string(path: Option<&PathBuf>) -> String {
let file = File::open(path.expect("Path cannot be None".into()))