diff options
Diffstat (limited to '')
-rw-r--r-- | src/auth.rs | 277 |
1 files changed, 193 insertions, 84 deletions
diff --git a/src/auth.rs b/src/auth.rs index c973921..82a09cb 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,9 +1,15 @@ -use nix::unistd::Group; +use nix::unistd::{User, Group, Uid, Gid}; use crate::{persist, secure}; +#[derive(Debug)] pub struct Config { - pub identitys: Vec<(String, bool)>, + pub permit: bool, + pub persist: bool, + pub nopass: bool, + pub user_uid: Option<Uid>, + pub user_gid: Option<Gid>, + pub privlaged_uid: Uid, } @@ -14,37 +20,132 @@ pub struct Config { /// * `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 - }; +/// * `Some(Vec<Config>)` - If the config was sucessfully parsed. +pub fn load_config_file(path: &str) -> Option<Vec<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}) + let mut configs = vec![]; + + for (line_num, line) in file.split("\n").enumerate() { + + let args: Vec<&str> = line.split(" ").collect(); + let len = args.len(); + + if line.starts_with("#") || line.trim() == "" { + continue; + } + + if len < 2 { + config_error(line_num, "Not enough arguments"); + continue; + } + + let permit = match args[0] { + "permit" => true, + "deny" => false, + _ => { + config_error(line_num, "The first argument must be `permit` or `deny"); + continue; + } + }; + + let (user_name, privlaged_name, as_index) = match args.iter().position(|&a| a == "as") { + Some(index) => { + if index != len - 2 { + config_error(line_num, "Target user not specified or to many arguments after `as`"); + continue; + } + (args[index-1].to_string(), args[index+1].to_string(), index) + }, + None => (args[len-1].to_string(), "root".to_string(), len-1) + }; + + let persist = args[1..as_index].contains(&"persist"); + + let nopass = args[1..as_index].contains(&"nopass"); + + + let (user_uid, user_gid) = + if user_name.starts_with(":") { + match get_gid_from_name(&user_name[1..]) { + Some(gid) => (None, Some(gid)), + None => { + config_error(line_num, &format!("Group `{}` does not exist", &user_name[1..])); + continue; + } + } + } else { + match get_uid_from_name(&user_name) { + Some(uid) => (Some(uid), None), + None => { + config_error(line_num, &format!("User `{}` does not exist", user_name)); + continue; + } + } + }; + + let privlaged_uid = match get_uid_from_name(&privlaged_name) { + Some(uid) => uid, + None => { + config_error(line_num, &format!("User `{}` does not exist", privlaged_name)); + continue; + } + }; + + configs.push(Config { + permit, + persist, + nopass, + user_uid, + user_gid, + privlaged_uid + }); + } + Some(configs) +} + + +fn config_error(line_num: usize, message: &str) { + eprintln!("Error in config at line {}: {}", line_num, message); +} + + +fn get_uid_from_name(name: &str) -> Option<Uid> { + return match User::from_name(name) { + Ok(result) => match result { + Some(data) => Some(data.uid), + None => None + }, + Err(_) => None + } +} + + +fn get_name_from_uid(uid: Uid) -> Option<String> { + return match User::from_uid(uid) { + Ok(result) => match result { + Some(data) => Some(data.name), + None => None + }, + Err(_) => None + } +} + + +fn get_gid_from_name(name: &str) -> Option<Gid> { + return match Group::from_name(name) { + Ok(result) => match result { + Some(data) => Some(data.gid), + None => None + }, + Err(_) => None + } } @@ -53,41 +154,44 @@ pub fn load_config(path: &str) -> Option<Config> { /// 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 +fn get_groups() -> Vec<Gid> { + let groups = match nix::unistd::getgroups() { + Ok(data) => data, + Err(_) => return vec![] + }; + groups } /// 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 +/// * `uid` - The uid 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 +/// * `None` - If the uid is not authorized +/// * `Some(Config)` - If the uid is authorized, returns the specific index of the associated config +pub fn authorize(configs: &Vec<Config>, uid: Uid) -> Option<usize> { + let groups = get_groups(); + for (config_index, config) in configs.iter().enumerate() { + if config.user_gid.is_some() { + if groups.contains(&config.user_gid.unwrap()) { + if config.permit { + return Some(config_index) + } else { + return None + } + } + } else if config.user_uid.is_some() { + if config.user_uid.unwrap() == uid { + if config.permit { + return Some(config_index) + } else { + return None + } + } + } + } + None } @@ -96,31 +200,36 @@ pub fn authorize(config: &Config, user: &str) -> Option<bool> { /// 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 +/// * `config` - The config associated with the user to authenticate with +/// * `force_pass` - Force a password prompt even if persistance is set to true +/// * `uid` - The user uid that is authenticating /// #### Returns -/// * `true` - If the user authenticated sucessfully, or the user is persisted +/// * `true` - If the user authenticated sucessfully /// * `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, +pub fn authenticate(config: &Config, force_pass: bool, uid: Uid) -> bool { + let name = match get_name_from_uid(uid) { + Some(data) => data, + None => return false + }; + if config.nopass || ( !force_pass && config.persist && persist::get_persist(&name) ) { + secure::elevate_privilages(config.privlaged_uid); + return true; + } + let input = match rpassword::prompt_password(format!("crab ({}) password: ", &name)) { + 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; + }; + auth.get_handler().set_credentials(&name, input); + if !auth.authenticate().is_ok() || !auth.open_session().is_ok() { + return false; + } + if config.persist { + persist::set_persist(&name); + } + secure::elevate_privilages(config.privlaged_uid); + return true; } |