summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--src/flags.rs58
-rw-r--r--src/help.rs11
-rw-r--r--src/main.rs137
-rw-r--r--src/persist.rs101
6 files changed, 197 insertions, 114 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a1b0e2b..30484cb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -34,7 +34,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crab"
-version = "0.0.1"
+version = "0.0.3"
dependencies = [
"exec",
"nix",
diff --git a/Cargo.toml b/Cargo.toml
index 9db50ac..b80305f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "crab"
-version = "0.0.1"
+version = "0.0.3"
edition = "2021"
[dependencies]
diff --git a/src/flags.rs b/src/flags.rs
new file mode 100644
index 0000000..91acf3a
--- /dev/null
+++ b/src/flags.rs
@@ -0,0 +1,58 @@
+pub struct Flags {
+ pub help: bool,
+ pub version: bool,
+ pub dont_persist: bool,
+ pub arg_count: usize
+}
+
+pub fn parse(args: &[String]) -> Flags {
+ let mut flags = Flags {
+ help: false,
+ version: false,
+ dont_persist: false,
+ arg_count: 0
+ };
+ for arg in args {
+ if !is_arg(&arg) { break; }
+ flags.arg_count += 1;
+ if arg.starts_with("--") {
+ let flag = &arg[2..];
+ check_flag(&flag, &mut flags);
+ } else {
+ let flag = &arg[1..];
+ for char in flag.chars() {
+ check_flag(&char.to_string(), &mut flags);
+ }
+ }
+ }
+ flags
+}
+
+fn is_arg(arg: &str) -> bool {
+ return arg.starts_with("-");
+}
+
+const HELP_FLAG: &str = "help h";
+const VERSION_FLAG: &str = "version v";
+const DONT_PERSIST: &str = "d";
+
+fn check_flag(arg: &str, flags: &mut Flags) {
+ if has_flag_set(&arg, HELP_FLAG) {
+ flags.help = true
+ }
+ if has_flag_set(&arg, VERSION_FLAG) {
+ flags.version = true
+ }
+ if has_flag_set(&arg, DONT_PERSIST) {
+ flags.dont_persist = true
+ }
+}
+
+fn has_flag_set(arg: &str, check: &str) -> bool {
+ for check_arg in check.split(" ") {
+ if check_arg == arg {
+ return true
+ }
+ }
+ return false
+} \ No newline at end of file
diff --git a/src/help.rs b/src/help.rs
new file mode 100644
index 0000000..422e35d
--- /dev/null
+++ b/src/help.rs
@@ -0,0 +1,11 @@
+pub fn help() {
+ let help =
+"Usage:
+ crab [-d] command [args]
+
+Options:
+ -v --version Get the current version of the package
+ -h --help Generates the crab help message
+ -d If your user is set to persist, dont save persistance";
+ println!("{}", help);
+} \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 9061ade..5fab1d9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,30 +1,35 @@
-use std::fs;
-use std::os::linux::fs::MetadataExt;
-use std::{env, os::unix::prelude::PermissionsExt};
+use std::env;
use std::process::ExitCode;
-use std::time::SystemTime;
use pwd::Passwd;
use nix::unistd;
-use serde_json::Value;
extern crate time;
-const ERROR_ARGS: u8 = 1;
+// const ERROR_COMMAND: u8 = 1;
const ERROR_CONFIG: u8 = 2;
const ERROR_NO_USER: u8 = 3;
const ERROR_NOT_AUTHORIZED: u8 = 4;
const ERROR_AUTH_FAILED: u8 = 5;
const ERROR_RUN_ROOT: u8 = 6;
-const SUCCESS: u8 = 0;
-
-const PERSIST_TIME: u64 = 60 * 3;
+mod persist;
+mod flags;
+mod help;
fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
- if args.len() < 2 {
- println!("usage: crab command [args]");
- return ExitCode::from(ERROR_ARGS);
+ let flags = flags::parse(&args[1..]);
+ if flags.version {
+ println!("crab version 0.0.3");
+ return ExitCode::SUCCESS;
+ }
+ if flags.help {
+ help::help();
+ return ExitCode::SUCCESS;
+ }
+ if args.len() - flags.arg_count < 2 {
+ println!("usage: crab [-d] command [args]");
+ return ExitCode::SUCCESS;
}
let config = match config("/etc/crab.conf") {
Some(data) => data,
@@ -38,7 +43,7 @@ fn main() -> ExitCode {
}
};
let persist = match allowed(&config, &user.name) {
- Some(data) => data,
+ Some(data) => data && !flags.dont_persist,
None => {
eprintln!("Operation Not Permitted.");
return ExitCode::from(ERROR_NOT_AUTHORIZED);
@@ -54,11 +59,12 @@ fn main() -> ExitCode {
eprintln!("Failed to set root permissions");
return ExitCode::from(ERROR_RUN_ROOT);
};
-
- let err = exec::execvp(&args[1], &args[1..]);
- println!("Error: {}", err);
+ let start = 1 + flags.arg_count;
+ let err = exec::execvp(&args[start], &args[start..]);
+
+ eprintln!("{}", err);
- ExitCode::from(SUCCESS)
+ ExitCode::SUCCESS
}
struct Config {
@@ -66,7 +72,7 @@ struct Config {
}
fn validate(user: &str, persist: bool) -> bool {
- if persist && get_persist(user) {
+ if persist && persist::get_persist(user) {
return true;
}
let input = match rpassword::prompt_password(format!("crab ({}) password: ", user)) {
@@ -82,7 +88,7 @@ fn validate(user: &str, persist: bool) -> bool {
return false;
}
if persist {
- set_persist(user);
+ persist::set_persist(user);
}
return true;
}
@@ -126,97 +132,4 @@ fn config(path: &str) -> Option<Config> {
users.push((user, persist));
}
Some(Config{users})
-}
-
-fn get_terminal_process() -> Option<i32> {
- let id: i32 = match std::process::id().try_into() {
- Ok(data) => data,
- Err(_) => return None
- };
- let stat = match procinfo::pid::stat(id) {
- Ok(data) => data,
- Err(_) => return None
- };
- Some(stat.session)
-}
-
-fn is_file_root_only(id: &i32) -> bool {
- let metadata = match std::fs::metadata(path(&id)) {
- Ok(data) => data,
- Err(e) => {
- if let Some(err) = e.raw_os_error() {
- return err == 2;
- }
- return true
- }
- };
- let perms = metadata.permissions();
- return perms.mode() == 33200 && metadata.st_uid() == 0 && metadata.st_gid() == 0;
-}
-
-fn get_terminal_config() -> Option<Value> {
- let id = match get_terminal_process() {
- Some(data) => data,
- None => return None
- };
- if !is_file_root_only(&id) {
- return None;
- }
- let data = match std::fs::read_to_string(path(&id)) {
- Ok(data) => data,
- Err(_) => "{}".to_string()
- };
- let json: Value = match serde_json::from_str(&data) {
- Ok(data) => data,
- Err(_) => return None
- };
- Some(json)
-}
-
-fn write_terminal_config(id: &i32, data: &str) -> Result<(), Box<dyn std::error::Error>> {
- std::fs::write(path(&id), data)?;
- unistd::chown(std::path::Path::new(&path(&id)), Some(unistd::Uid::from(0)), Some(unistd::Gid::from(0)))?;
- let metadata = std::fs::metadata(path(&id))?;
- let mut perms = metadata.permissions();
- perms.set_mode(0o660);
- fs::set_permissions(path(&id), perms)?;
- Ok(())
-}
-
-fn get_persist(user: &str) -> bool {
- let json = match get_terminal_config() {
- Some(data) => data,
- None => return false
- };
- let timestamp = match json[user].as_u64() {
- Some(data) => data,
- None => return false
- };
- return now() - timestamp < PERSIST_TIME;
-}
-
-fn set_persist(user: &str) {
- let mut json = match get_terminal_config() {
- Some(data) => data,
- None => return
- };
- json[user] = Value::from(now());
- let id = match get_terminal_process() {
- Some(data) => data,
- None => return
- };
- match write_terminal_config(&id, &json.to_string()) {
- Ok(_) => {},
- Err(e) => {
- eprintln!("Internal Error: {}", e)
- }
- };
-}
-
-fn now() -> u64 {
- return SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
-}
-
-fn path(id: &i32) -> String {
- return format!("/tmp/crab-{}", id);
} \ No newline at end of file
diff --git a/src/persist.rs b/src/persist.rs
new file mode 100644
index 0000000..7d47232
--- /dev/null
+++ b/src/persist.rs
@@ -0,0 +1,101 @@
+use std::fs;
+use std::os::linux::fs::MetadataExt;
+use std::os::unix::prelude::PermissionsExt;
+use std::time::SystemTime;
+use nix::unistd;
+use serde_json::Value;
+
+const PERSIST_TIME: u64 = 60 * 3;
+
+pub fn get_persist(user: &str) -> bool {
+ let json = match get_terminal_config() {
+ Some(data) => data,
+ None => return false
+ };
+ let timestamp = match json[user].as_u64() {
+ Some(data) => data,
+ None => return false
+ };
+ return now() - timestamp < PERSIST_TIME;
+}
+
+pub fn set_persist(user: &str) {
+ let mut json = match get_terminal_config() {
+ Some(data) => data,
+ None => return
+ };
+ json[user] = Value::from(now());
+ let id = match get_terminal_process() {
+ Some(data) => data,
+ None => return
+ };
+ match write_terminal_config(&id, &json.to_string()) {
+ Ok(_) => {},
+ Err(e) => {
+ eprintln!("Internal Error: {}", e)
+ }
+ };
+}
+
+fn get_terminal_process() -> Option<i32> {
+ let id: i32 = match std::process::id().try_into() {
+ Ok(data) => data,
+ Err(_) => return None
+ };
+ let stat = match procinfo::pid::stat(id) {
+ Ok(data) => data,
+ Err(_) => return None
+ };
+ Some(stat.session)
+}
+
+fn is_file_root_only(id: &i32) -> bool {
+ let metadata = match std::fs::metadata(path(&id)) {
+ Ok(data) => data,
+ Err(e) => {
+ if let Some(err) = e.raw_os_error() {
+ return err == 2;
+ }
+ return true
+ }
+ };
+ let perms = metadata.permissions();
+ return perms.mode() == 33200 && metadata.st_uid() == 0 && metadata.st_gid() == 0;
+}
+
+fn get_terminal_config() -> Option<Value> {
+ let id = match get_terminal_process() {
+ Some(data) => data,
+ None => return None
+ };
+ if !is_file_root_only(&id) {
+ return None;
+ }
+ let data = match std::fs::read_to_string(path(&id)) {
+ Ok(data) => data,
+ Err(_) => "{}".to_string()
+ };
+ let json: Value = match serde_json::from_str(&data) {
+ Ok(data) => data,
+ Err(_) => return None
+ };
+ Some(json)
+}
+
+fn write_terminal_config(id: &i32, data: &str) -> Result<(), Box<dyn std::error::Error>> {
+ std::fs::write(path(&id), data)?;
+ unistd::chown(std::path::Path::new(&path(&id)), Some(unistd::Uid::from(0)), Some(unistd::Gid::from(0)))?;
+ let metadata = std::fs::metadata(path(&id))?;
+ let mut perms = metadata.permissions();
+ perms.set_mode(0o660);
+ fs::set_permissions(path(&id), perms)?;
+ Ok(())
+}
+
+fn now() -> u64 {
+ return SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
+}
+
+fn path(id: &i32) -> String {
+ return format!("/tmp/crab-{}", id);
+} \ No newline at end of file