use std::{env, error::Error};
use clap::ArgMatches;
use log::{debug, info};
use pam_client::{conv_cli::Conversation, Flag, Session};
use crate::{auth, cmd, cmd::CmdData, config, user, utils};
pub(crate) fn run(matches: &ArgMatches<'_>) -> Result<(), Box<dyn Error>> {
debug!("Starting configuration initialization");
let mut conf = config::init_conf()?;
debug!("Starting extraction of User information");
let userdata = user::User::new()?;
debug!(
"Starting extraction of the vector of UserConf tie to {} in rudo.conf",
&userdata.username
);
let mut userconf = config::extract_userconf(conf.user.clone(), &userdata.username);
if matches.is_present("greeting") {
debug!("Update configuration with CLI option as it as the priority");
userconf = config::UserConf::update_greeting(userconf);
}
if matches.is_present("user") {
let impuser = match matches.value_of("user") {
Some(user) => user.to_owned(),
None => return Err(From::from("user value couldn't be found!")),
};
conf = config::Config::update_user(conf, impuser);
}
debug!(
"Extract UID and GID of the impersonated user {}",
&conf.rudo.impuser
);
let impuser = match users::get_user_by_name(&conf.rudo.impuser) {
Some(impuser) => impuser,
None => return Err(From::from("Please give Rudo a real unix username")),
};
if userconf.greeting {
debug!("Start user greeting messages and disclaimer");
println!(
"Hello {}! Think carefully before using Rudo.",
userdata.username
);
}
debug!(
"Authenticate {} with the list in rudo.conf",
userdata.username
);
auth::authentification(&userconf, &userdata)?;
debug!(
"Pam context initialization and identification of {}",
userdata.username
);
let mut context = auth::authentification_pam(&conf, &userconf, &userdata)?;
debug!("Session initialize with Pam credential");
let session = context.open_session(Flag::NONE)?;
debug!("Run the command {} as choose", userdata.username);
run_command(matches, &session, &impuser, &userdata)?;
Ok(())
}
fn run_command(
matches: &ArgMatches<'_>,
session: &Session<'_, Conversation>,
impuser: &users::User,
userdata: &user::User,
) -> Result<(), Box<dyn Error>> {
if matches.is_present("command") {
debug!("Extracting the supply command for further use");
let command: Vec<&str> = match matches.values_of("command") {
Some(command) => command.collect(),
None => {
return Err(From::from(
"Command couldn't be converted to a vector of &str",
))
}
};
let data = cmd::CmdData::new(command)?;
let args = utils::vec_to_string(data.args.clone());
info!(
"{} has been authorized. Command: {} {}",
userdata.username, data.program, args
);
cmd::start_command(data, session, impuser)?;
} else if matches.is_present("shell") {
debug!("Extracting shell environment variable");
let shell = env::var("SHELL").unwrap_or_else(|_| String::from("/bin/sh"));
info!("{} has been authorized to use {}", userdata.username, shell);
let data = CmdData {
program: shell,
args: vec!["-l"],
};
cmd::start_command(data, session, impuser)?;
} else if matches.is_present("edit") {
debug!("Extracting editor environment variable");
let editor = env::var("EDITOR")?;
debug!("Extracting arguments and file path give to the editor");
let arg = match matches.value_of("edit") {
Some(arg) => arg,
None => return Err(From::from("Error couldn't pass value of edit to a &str")),
};
info!(
"{} has been authorized to use {} {}",
userdata.username, editor, arg
);
let data = CmdData {
program: editor,
args: vec![arg],
};
cmd::start_command(data, session, impuser)?;
} else {
return Err(From::from(
"You shouldn't be able to see this error. CLI should have stopped you",
));
}
Ok(())
}