diff options
Diffstat (limited to 'src/auth.rs')
-rw-r--r-- | src/auth.rs | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..c973921 --- /dev/null +++ b/src/auth.rs @@ -0,0 +1,126 @@ +use nix::unistd::Group; +use crate::{persist, secure}; + + +pub struct Config { + pub identitys: Vec<(String, bool)>, +} + + +/// Returns a option containing the config ad the specific pile path. +/// This function will print out config syntax errors to the standard +/// output if it failes to parse certain lines. +/// #### Arguments +/// * `path` - The path to the config file +/// #### Returns +/// * `None` - If the config failed to load +/// * `Some(Config)` - If the config was sucessfully parsed. +pub fn load_config(path: &str) -> Option<Config> { + let file = match std::fs::read_to_string(path) { + Err(e) => { + eprintln!("{}: {}", &path, e); + return None + }, + Ok(data) => data + }; + + let mut identitys = vec![]; + for (line_num, line) in file.split("\n").enumerate() { + let args: Vec<&str> = line.split(" ").collect(); + if line.starts_with("#") || line.trim() == "" { + continue; + } + if args.len() < 2 { + eprintln!("Error in config at line {}: Not enough arguments", line_num); + continue; + } + let identity: String = args[0].to_string(); + let persist: bool = match args[1].parse() { + Err(e) => { + eprintln!("Error in config at line {}: {}", line_num, e); + continue; + }, + Ok(data) => data + }; + identitys.push((identity, persist)); + } + Some(Config{identitys}) +} + + +/// Returns a vector of group names of the groups the current effective uid is in +/// #### Returns +/// A vector of strings of the groups the user is in. If the vector is empty, +/// either the function coudn't retrieve the users groups, or the user is not in +/// any groups. +fn get_groups() -> Vec<String> { + let groups = match nix::unistd::getgroups() { + Ok(data) => data, + Err(_) => return vec![] + }; + let names = groups.iter() + .map(|gid| Group::from_gid(*gid)) + .flatten().flatten() + .map(|group| group.name) + .collect(); + names +} + + +/// Returns if the user is authorized given a sepcific config and user name. +/// #### Arguments +/// * `config` - A config struct contaning the authorization settings for crab +/// * `user` - The name of the user to check is authorized +/// #### Returns +/// * `None` - If the user is not authorized +/// * `Some(bool)` - If the user is authorized, returning the boolean if the +/// user is set to persist +pub fn authorize(config: &Config, user: &str) -> Option<bool> { + let groups = get_groups(); + for (identity, persist) in &config.identitys { + if identity.starts_with(":") { + let group = &identity[1..]; + if groups.contains(&group.to_string()) { + return Some(persist.clone()); + }; + } else if identity == user { + return Some(persist.clone()); + } + } + None +} + + +/// Authenticates an authorized user for the current session. +/// If the user is already persisted, it will attempt to +/// read the persist file, and then skip authentication if +/// the is still persisted. +/// #### Arguments +/// * `user` - The login name of the linux user +/// * `persist` - If the user's login should persist +/// #### Returns +/// * `true` - If the user authenticated sucessfully, or the user is persisted +/// * `false` - If the user failed to authenticate +pub fn authenticate(user: &str, persist: bool) -> bool { + if persist && persist::get_persist(user) { + secure::elevate_privilages(0, 0); + return true; + } + let input = match rpassword::prompt_password(format!("crab ({}) password: ", user)) { + Ok(data) => data, + Err(_) => return false + }; + let mut auth = match pam::Authenticator::with_password("crab") { + Ok(data) => data, + Err(_) => return false + }; + auth.get_handler().set_credentials(user.to_owned(), input); + if !auth.authenticate().is_ok() || !auth.open_session().is_ok() { + return false; + } + if persist { + persist::set_persist(user); + } + secure::elevate_privilages(0, 0); + return true; +} |