summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortylermurphy534 <tylermurphy534@gmail.com>2022-11-11 09:56:48 -0500
committertylermurphy534 <tylermurphy534@gmail.com>2022-11-11 09:56:48 -0500
commitde24d5499ac83f426228b28b90bed8f26e68fb3b (patch)
tree7a37f98005e8337d078db9edf1fec89de4a98f04
parentupdate config format (diff)
downloadcrab-de24d5499ac83f426228b28b90bed8f26e68fb3b.tar.gz
crab-de24d5499ac83f426228b28b90bed8f26e68fb3b.tar.bz2
crab-de24d5499ac83f426228b28b90bed8f26e68fb3b.zip
doc string, refactor, config token error
-rw-r--r--readme.md14
-rw-r--r--src/auth.rs51
-rw-r--r--src/main.rs15
-rw-r--r--src/persist.rs28
-rw-r--r--src/secure.rs19
5 files changed, 90 insertions, 37 deletions
diff --git a/readme.md b/readme.md
index 971c469..7d6566d 100644
--- a/readme.md
+++ b/readme.md
@@ -12,11 +12,19 @@ Run `uninstall.sh` as root to uninstall crab.
If you are on an arch based distro, crab is avaliable on the [AUR](https://aur.archlinux.org/packages/crab) as `crab`.
# Configuration
-Crab supports multiple users with persistence. Each line of the config is the username, then `true` of `false` if the crab authentication persists.
+Each line in the configuration specifies a different rule. Each rule is applied from top to bottom,
+so the first onethat matches a user is what is used. The first word is either `permit` or `deny` to
+allow or deny a certain group. Then the tags `persist` and `nopass` can be added to allow authoriziation
+persistance or skipping respectively. Then a user can be specified by putting their name, or a group by a
+colon then the groups name. Finally, if you dont want to run that user as root, you can add `as` and then
+a user name to run the process as. All lines starting in a # will be ignored.
For Example
```
-root true
-tylerm false
+deny :docker
+permit nopass persist linus as root
+permit :wheel persist
+#deny stallman
+permit nvidia as fu
```
The default configuration file is stored in `/usr/share/crab/crab.conf` and must be coppied to `/etc/crab.conf`.
diff --git a/src/auth.rs b/src/auth.rs
index 82a09cb..99a8216 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -1,8 +1,7 @@
-use nix::unistd::{User, Group, Uid, Gid};
-use crate::{persist, secure};
+use nix::unistd::{User, Group, Uid, Gid, self};
+use crate::persist;
-#[derive(Debug)]
pub struct Config {
pub permit: bool,
pub persist: bool,
@@ -55,20 +54,31 @@ pub fn load_config_file(path: &str) -> Option<Vec<Config>> {
}
};
- let (user_name, privlaged_name, as_index) = match args.iter().position(|&a| a == "as") {
+ let (user_name, privlaged_name, name_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)
+ (args[index-1].to_string(), args[index+1].to_string(), index-1)
},
None => (args[len-1].to_string(), "root".to_string(), len-1)
};
- let persist = args[1..as_index].contains(&"persist");
+ let persist = args[1..name_index].contains(&"persist");
- let nopass = args[1..as_index].contains(&"nopass");
+ let nopass = args[1..name_index].contains(&"nopass");
+
+
+ for &check in args[1..name_index].iter() {
+ match check {
+ "persist" => continue,
+ "nopass" => continue,
+ _ => {
+ config_error(line_num, &format!("Unexpected token `{}`", check))
+ }
+ }
+ }
let (user_uid, user_gid) =
@@ -111,11 +121,18 @@ pub fn load_config_file(path: &str) -> Option<Vec<Config>> {
}
+/// Print a crab config error to the standard output
fn config_error(line_num: usize, message: &str) {
eprintln!("Error in config at line {}: {}", line_num, message);
}
+/// Returns a Uid from a Users name
+/// #### Arguments
+/// * `name` - The name of the user
+/// #### Returns
+/// * `None` - If the user doesn't exist
+/// * `Some(Gid)` - If the user exists
fn get_uid_from_name(name: &str) -> Option<Uid> {
return match User::from_name(name) {
Ok(result) => match result {
@@ -127,6 +144,12 @@ fn get_uid_from_name(name: &str) -> Option<Uid> {
}
+/// Returns a Uesrs name from a Uid
+/// #### Arguments
+/// * `uid` - The uid of the user
+/// #### Returns
+/// * `None` - If the user doesn't exist
+/// * `Some(Gid)` - If the user exists
fn get_name_from_uid(uid: Uid) -> Option<String> {
return match User::from_uid(uid) {
Ok(result) => match result {
@@ -138,6 +161,12 @@ fn get_name_from_uid(uid: Uid) -> Option<String> {
}
+/// Returns a Gid from a Groups name
+/// #### Arguments
+/// * `name` - The name of the group
+/// #### Returns
+/// * `None` - If the group doesn't exist
+/// * `Some(Gid)` - If the group exists
fn get_gid_from_name(name: &str) -> Option<Gid> {
return match Group::from_name(name) {
Ok(result) => match result {
@@ -155,7 +184,7 @@ fn get_gid_from_name(name: &str) -> Option<Gid> {
/// either the function coudn't retrieve the users groups, or the user is not in
/// any groups.
fn get_groups() -> Vec<Gid> {
- let groups = match nix::unistd::getgroups() {
+ let groups = match unistd::getgroups() {
Ok(data) => data,
Err(_) => return vec![]
};
@@ -212,7 +241,6 @@ pub fn authenticate(config: &Config, force_pass: bool, uid: Uid) -> bool {
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)) {
@@ -227,9 +255,10 @@ pub fn authenticate(config: &Config, force_pass: bool, uid: Uid) -> bool {
if !auth.authenticate().is_ok() || !auth.open_session().is_ok() {
return false;
}
- if config.persist {
+ if !force_pass && config.persist {
persist::set_persist(&name);
+ } else if force_pass {
+ persist::remove_persist(&name);
}
- secure::elevate_privilages(config.privlaged_uid);
return true;
}
diff --git a/src/main.rs b/src/main.rs
index cca85de..56df611 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,10 +8,11 @@ mod persist;
mod secure;
-const ERROR_ARGS: u8 = 1;
-const ERROR_CONFIG: u8 = 2;
-const ERROR_NOT_AUTHORIZED: u8 = 3;
-const ERROR_AUTH_FAILED: u8 = 4;
+const ERROR_ARGS: u8 = 1;
+const ERROR_CONFIG: u8 = 2;
+const ERROR_NOT_AUTHORIZED: u8 = 3;
+const ERROR_AUTH_FAILED: u8 = 4;
+const ERROR_ELEVATE_PRIVILEGES: u8 = 5;
fn main() -> ExitCode {
@@ -69,6 +70,12 @@ fn main() -> ExitCode {
return ExitCode::from(ERROR_AUTH_FAILED);
}
+ // elevate privileges
+ if nix::unistd::setuid(configs[auth].privlaged_uid).is_err() {
+ eprintln!("Failed to elevate privileges.");
+ return ExitCode::from(ERROR_ELEVATE_PRIVILEGES);
+ };
+
// execute the passed command
let start = 1 + flags.arg_count;
let err = exec::execvp(&args[start], &args[start..]);
diff --git a/src/persist.rs b/src/persist.rs
index 762d8b1..2bca386 100644
--- a/src/persist.rs
+++ b/src/persist.rs
@@ -28,7 +28,7 @@ pub fn get_persist(user: &str) -> bool {
}
-/// Updates the current sessions persist file
+/// Updates a user in the current sessions persist file
/// #### Arguments
/// * `user` - The user to set persisted
pub fn set_persist(user: &str) {
@@ -43,8 +43,30 @@ pub fn set_persist(user: &str) {
};
match secure::write_file(PERSIST_PATH, &format!("{}", session), &json.to_string()) {
Ok(_) => {},
- Err(e) => {
- eprintln!("crab: An Internal Has Error: {}", e);
+ Err(_) => {
+ eprintln!("crab: An internal error has occured");
+ }
+ };
+}
+
+
+/// Removes a user from the current sessions persist file
+/// #### Arguments
+/// * `user` - The user to set non-persisted
+pub fn remove_persist(user: &str) {
+ let mut json = match get_persist_config() {
+ Some(data) => data,
+ None => return
+ };
+ json[user] = Value::from(0);
+ let session = match get_current_session() {
+ Some(data) => data,
+ None => return
+ };
+ match secure::write_file(PERSIST_PATH, &format!("{}", session), &json.to_string()) {
+ Ok(_) => {},
+ Err(_) => {
+ eprintln!("crab: An internal error has occured");
}
};
}
diff --git a/src/secure.rs b/src/secure.rs
index 018bc4f..7c85ece 100644
--- a/src/secure.rs
+++ b/src/secure.rs
@@ -1,5 +1,5 @@
-use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io::{self, ErrorKind}};
-use nix::unistd::{self, Uid};
+use std::{os::{unix::prelude::PermissionsExt, linux::fs::MetadataExt}, fs, io::{self, ErrorKind}, path::Path};
+use nix::unistd::{self, Uid, Gid};
/// Writes a file securly to a specified path with given data
@@ -40,19 +40,6 @@ pub fn read_file(dir: &str, file: &str) -> Option<String> {
}
-/// Elecate the privlages of the current process
-/// #### Arguments
-/// * `uid` - The uid to set the process to
-/// #### Returns
-/// If the process fails to elevate, it returns false
-pub fn elevate_privilages(uid: Uid) -> bool {
- if unistd::setuid(uid).is_err() {
- return false;
- }
- true
-}
-
-
/// Sets the permission for a secure file
/// #### Arguments
/// * `uid` - The user to own the file
@@ -62,7 +49,7 @@ pub fn elevate_privilages(uid: Uid) -> bool {
/// #### Returns
/// A ``io::Result<()>`` if the write succeded or failed
fn set_file_permissions(uid: u32, gid: u32, mode: u32, path: &str) -> Result<(), io::Error> {
- unistd::chown(std::path::Path::new(path), Some(unistd::Uid::from(uid)), Some(unistd::Gid::from(gid)))?;
+ unistd::chown(Path::new(path), Some(Uid::from(uid)), Some(Gid::from(gid)))?;
let metadata = fs::metadata(path)?;
let mut perms = metadata.permissions();
perms.set_mode(mode);