summaryrefslogtreecommitdiff
path: root/src/auth.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/auth.rs277
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;
}