use std::env; use std::process::ExitCode; use pwd::Passwd; use nix::unistd; extern crate time; // 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; mod persist; mod flags; mod help; fn main() -> ExitCode { let args: Vec = env::args().collect(); 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, None => return ExitCode::from(ERROR_CONFIG) }; let user = match Passwd::current_user() { Some(data) => data, None => { eprintln!("You dont exist."); return ExitCode::from(ERROR_NO_USER); } }; let persist = match allowed(&config, &user.name) { Some(data) => data && !flags.dont_persist, None => { eprintln!("Operation Not Permitted."); return ExitCode::from(ERROR_NOT_AUTHORIZED); } }; if !validate(&user.name, persist) { eprintln!("Authentication failed."); return ExitCode::from(ERROR_AUTH_FAILED); } if !unistd::setuid(unistd::geteuid()).is_ok() || !unistd::setgid(unistd::getegid()).is_ok() { eprintln!("Failed to set root permissions"); return ExitCode::from(ERROR_RUN_ROOT); }; let start = 1 + flags.arg_count; let err = exec::execvp(&args[start], &args[start..]); eprintln!("{}", err); ExitCode::SUCCESS } struct Config { users: Vec<(String, bool)> } fn validate(user: &str, persist: bool) -> bool { if persist && persist::get_persist(user) { 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); } return true; } fn allowed(config: &Config, user: &str) -> Option { for (name, persist) in &config.users { if name == user { return Some(persist.clone()); } } None } fn config(path: &str) -> Option { let file = match std::fs::read_to_string(path) { Err(e) => { eprintln!("{}: {}", &path, e); return None }, Ok(data) => data }; let mut users = vec![]; for (line_num, line) in file.split("\n").enumerate() { let args: Vec<&str> = line.split(" ").collect(); if line.trim() == "" { continue; } if args.len() < 2 { eprintln!("Error in config at line {}: Not enough arguments", line_num); continue; } let user: 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 }; users.push((user, persist)); } Some(Config{users}) }