use std::{cell::RefCell, collections::HashMap, error::Error, rc::Rc};
use indexmap::IndexSet;
use jiff::SignedDuration;
use log::{debug, warn};
use crate::cli::data::{InputAction, RoleType, SetListType, TaskType, TimeoutOpt};
use rootasrole_core::database::{
options::{
EnvBehavior, EnvKey, Opt, OptStack, OptType, PathBehavior, SEnvOptions, SPathOptions,
STimeout, SUMask, SWorkdirEither, SWorkdirSet, WorkdirBehavior,
},
structs::{
IdTask, RoleGetter, SCapabilities, SCommand, SGroupsEither, SRole, STask, SUserEither,
},
};
use super::perform_on_target_opt;
pub fn list_json(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options: bool,
options_type: Option<OptType>,
task_type: Option<TaskType>,
role_type: Option<RoleType>,
) -> Result<(), Box<dyn Error>> {
let config = rconfig.as_ref().borrow();
role_id.map_or_else(
|| {
println!(
"{}",
serde_json::to_string_pretty(&*config)
.unwrap_or_else(|_| "Failed to serialize config".to_string())
);
Ok(())
},
|role_id| {
rconfig.role(role_id).map_or_else(
|| Err("Role not found".into()),
|role| list_task(task_id, &role, options, options_type, task_type, role_type),
)
},
)
}
fn list_task(
task_id: Option<IdTask>,
role: &Rc<RefCell<rootasrole_core::database::structs::SRole>>,
options: bool,
options_type: Option<OptType>,
task_type: Option<TaskType>,
role_type: Option<RoleType>,
) -> Result<(), Box<dyn Error>> {
if let Some(task_id) = task_id {
if let Some(task) = role.as_ref().borrow().task(&task_id) {
if options {
debug!("task {task:?}");
let rcopt = OptStack::from_task(&task.clone())
.to_opt()
.map_err(std::io::Error::other)?;
let opt = rcopt.as_ref().borrow();
if let Some(opttype) = options_type {
match opttype {
OptType::Env => {
println!("{}", serde_json::to_string_pretty(&opt.env)?);
}
OptType::Path => {
println!("{}", serde_json::to_string_pretty(&opt.path)?);
}
OptType::Root => {
println!("{}", serde_json::to_string_pretty(&opt.root)?);
}
OptType::Bounding => {
println!("{}", serde_json::to_string_pretty(&opt.bounding)?);
}
OptType::Timeout => {
println!("{}", serde_json::to_string_pretty(&opt.timeout)?);
}
OptType::Authentication => {
println!("{}", serde_json::to_string_pretty(&opt.authentication)?);
}
OptType::ExecInfo => {
println!("{}", serde_json::to_string_pretty(&opt.execinfo)?);
}
OptType::UMask => {
println!("{}", serde_json::to_string_pretty(&opt.umask)?);
}
OptType::Workdir => {
println!("{}", serde_json::to_string_pretty(&opt.workdir)?);
}
}
} else {
println!("{}", serde_json::to_string_pretty(&rcopt)?);
}
} else {
print_task(task, task_type.unwrap_or(TaskType::All))?;
}
} else {
return Err("Task not found".into());
}
} else if options {
let rcopt = OptStack::from_role(&role.clone())
.to_opt()
.map_err(std::io::Error::other)?;
println!("{}", serde_json::to_string_pretty(&rcopt)?);
} else {
print_role(role, role_type.unwrap_or(RoleType::All))?;
}
Ok(())
}
fn print_task(
task: &std::rc::Rc<std::cell::RefCell<rootasrole_core::database::structs::STask>>,
task_type: TaskType,
) -> Result<(), Box<dyn std::error::Error>> {
match task_type {
TaskType::All => {
println!("{}", serde_json::to_string_pretty(&task)?);
}
TaskType::Commands => {
println!(
"{}",
serde_json::to_string_pretty(&task.as_ref().borrow().commands)?
);
}
TaskType::Credentials => {
println!(
"{}",
serde_json::to_string_pretty(&task.as_ref().borrow().cred)?
);
}
}
Ok(())
}
fn print_role(
role: &std::rc::Rc<std::cell::RefCell<rootasrole_core::database::structs::SRole>>,
role_type: RoleType,
) -> Result<(), Box<dyn std::error::Error>> {
match role_type {
RoleType::All => {
println!("{}", serde_json::to_string_pretty(&role)?);
}
RoleType::Actors => {
println!(
"{}",
serde_json::to_string_pretty(&role.as_ref().borrow().actors)?
);
}
RoleType::Tasks => {
println!(
"{}",
serde_json::to_string_pretty(&role.as_ref().borrow().tasks)?
);
}
}
Ok(())
}
pub fn role_add_del(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
action: InputAction,
role_id: String,
role_type: Option<RoleType>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 {action:?}");
match action {
InputAction::Add => {
if rconfig.role(&role_id).is_some() {
return Err("Role already exists".into());
}
rconfig
.as_ref()
.borrow_mut()
.roles
.push(SRole::builder(role_id).build());
Ok(true)
}
InputAction::Del => {
if rconfig.role(&role_id).is_none() {
return Err("Role do not exists".into());
}
rconfig
.as_ref()
.borrow_mut()
.roles
.retain(|r| r.as_ref().borrow().name != role_id);
Ok(true)
}
InputAction::Purge => {
if rconfig.role(&role_id).is_none() {
return Err("Role do not exists".into());
}
let role = rconfig.role(&role_id).ok_or("Role not found")?;
match role_type {
Some(RoleType::Actors) => {
role.as_ref().borrow_mut().actors.clear();
}
Some(RoleType::Tasks) => {
role.as_ref().borrow_mut().tasks.clear();
}
None | Some(RoleType::All) => {
role.as_ref().borrow_mut().actors.clear();
role.as_ref().borrow_mut().tasks.clear();
}
}
Ok(true)
}
_ => Ok(false),
}
}
pub fn task_add_del(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
action: InputAction,
task_id: IdTask,
task_type: Option<TaskType>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 add|del");
let role = rconfig.role(role_id).ok_or("Role not found")?;
match action {
InputAction::Add => {
if role
.as_ref()
.borrow()
.tasks
.iter()
.any(|t| t.as_ref().borrow().name == task_id)
{
return Err("Task already exists".into());
}
role.as_ref()
.borrow_mut()
.tasks
.push(STask::builder(task_id).build());
Ok(true)
}
InputAction::Del => {
if role
.as_ref()
.borrow()
.tasks
.iter()
.all(|t| t.as_ref().borrow().name != task_id)
{
return Err("Task do not exists".into());
}
role.as_ref()
.borrow_mut()
.tasks
.retain(|t| t.as_ref().borrow().name != task_id);
Ok(true)
}
InputAction::Purge => {
let borrow = &role.as_ref().borrow();
let task = borrow.task(&task_id).expect("Task do not exists");
match task_type {
Some(TaskType::Commands) => {
task.as_ref().borrow_mut().commands.add.clear();
task.as_ref().borrow_mut().commands.sub.clear();
task.as_ref().borrow_mut().commands.default = None;
}
Some(TaskType::Credentials) => {
task.as_ref().borrow_mut().cred.capabilities = None;
task.as_ref().borrow_mut().cred.setuid = None;
task.as_ref().borrow_mut().cred.setgid = None;
}
None | Some(TaskType::All) => {
task.as_ref().borrow_mut().commands.add.clear();
task.as_ref().borrow_mut().commands.sub.clear();
task.as_ref().borrow_mut().commands.default = None;
task.as_ref().borrow_mut().cred.capabilities = None;
task.as_ref().borrow_mut().cred.setuid = None;
task.as_ref().borrow_mut().cred.setgid = None;
}
}
Ok(true)
}
_ => unreachable!("Invalid action"),
}
}
pub fn grant_revoke(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
action: InputAction,
mut actors: Vec<rootasrole_core::database::actor::SActor>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 grant|revoke");
let role = rconfig.role(role_id).ok_or("Role not found")?;
match action {
InputAction::Add => {
actors.retain(|a| {
if role.as_ref().borrow().actors.contains(a) {
println!("Actor {a} already in role");
false
} else {
true
}
});
role.as_ref().borrow_mut().actors.extend(actors);
Ok(true)
}
InputAction::Del => {
if !role.as_ref().borrow().actors.contains(&actors[0]) {
println!("Actor {} not in role", actors[0]);
}
role.as_ref()
.borrow_mut()
.actors
.retain(|a| !actors.contains(a));
Ok(true)
}
_ => unreachable!("Invalid action"),
}
}
pub fn cred_set(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
cred_caps: Option<capctl::CapSet>,
cred_setuid: Option<rootasrole_core::database::actor::SUserType>,
cred_setgid: Option<rootasrole_core::database::actor::SGroups>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 cred");
match rconfig.task(role_id, task_id) {
Ok(task) => {
if let Some(caps) = cred_caps {
task.as_ref().borrow_mut().cred.capabilities = Some(SCapabilities::from(caps));
}
if let Some(setuid) = cred_setuid {
task.as_ref().borrow_mut().cred.setuid = Some(SUserEither::MandatoryUser(setuid));
}
if let Some(setgid) = cred_setgid {
task.as_ref().borrow_mut().cred.setgid =
Some(SGroupsEither::MandatoryGroups(setgid));
}
Ok(true)
}
Err(e) => Err(e),
}
}
pub fn cred_unset(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
cred_caps: Option<capctl::CapSet>,
cred_setuid: Option<&rootasrole_core::database::actor::SUserType>,
cred_setgid: Option<&rootasrole_core::database::actor::SGroups>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 cred unset");
match rconfig.task(role_id, task_id) {
Ok(task) => {
if let Some(caps) = cred_caps {
if caps.is_empty() {
task.as_ref().borrow_mut().cred.capabilities = None;
} else if let Some(ccaps) = task.as_ref().borrow_mut().cred.capabilities.as_mut() {
ccaps.add.drop_all(caps);
} else {
return Err("No capabilities to remove".into());
}
}
if cred_setuid.is_some() {
task.as_ref().borrow_mut().cred.setuid = None;
}
if cred_setgid.is_some() {
task.as_ref().borrow_mut().cred.setgid = None;
}
Ok(true)
}
Err(e) => Err(e),
}
}
pub fn cred_caps(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
setlist_type: SetListType,
action: InputAction,
cred_caps: capctl::CapSet,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 cred caps");
let task = rconfig.task(role_id, task_id)?;
match setlist_type {
SetListType::White => match action {
InputAction::Add => {
let mut borrow = task.as_ref().borrow_mut();
let caps = borrow.cred.capabilities.get_or_insert_default();
caps.add = caps.add.union(cred_caps);
debug!("caps.add: {:?}, cred_caps : {:?}", caps.add, cred_caps);
}
InputAction::Del => {
task.as_ref()
.borrow_mut()
.cred
.capabilities
.as_mut()
.ok_or("No capabilities to remove from the add set")?
.add
.drop_all(cred_caps);
}
InputAction::Set => {
task.as_ref()
.borrow_mut()
.cred
.capabilities
.get_or_insert_default()
.add = cred_caps;
}
_ => unreachable!("Unknown action {:?}", action),
},
SetListType::Black => match action {
InputAction::Add => {
let mut borrow = task.as_ref().borrow_mut();
let caps = borrow.cred.capabilities.get_or_insert_default();
caps.sub = caps.sub.union(cred_caps);
}
InputAction::Del => {
task.as_ref()
.borrow_mut()
.cred
.capabilities
.as_mut()
.ok_or("Cannot remove capabilities from an empty del")?
.sub
.drop_all(cred_caps);
}
InputAction::Set => {
task.as_ref()
.borrow_mut()
.cred
.capabilities
.get_or_insert_default()
.sub = cred_caps;
}
_ => unreachable!("Unknown action {:?}", action),
},
_ => unreachable!("Unknown setlist type"),
}
Ok(true)
}
pub fn cred_setpolicy(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
cred_policy: rootasrole_core::database::structs::SetBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 cred setpolicy");
let task = rconfig.task(role_id, task_id)?;
if task.as_ref().borrow_mut().cred.capabilities.is_none() {
task.as_ref()
.borrow_mut()
.cred
.capabilities
.replace(SCapabilities::default());
}
task.as_ref()
.borrow_mut()
.cred
.capabilities
.get_or_insert_default()
.default_behavior = cred_policy;
Ok(true)
}
pub fn cmd_whitelist_action(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
cmd_id: impl IntoIterator<Item = String>,
setlist_type: SetListType,
action: InputAction,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 command whitelist add c1");
let task = rconfig.task(role_id, task_id)?;
let cmd = SCommand::Simple(shell_words::join(cmd_id));
match setlist_type {
SetListType::White => match action {
InputAction::Add => {
if task.as_ref().borrow().commands.add.contains(&cmd) {
return Err("Command already exists".into());
}
task.as_ref().borrow_mut().commands.add.push(cmd);
}
InputAction::Del => {
if !task.as_ref().borrow().commands.add.contains(&cmd) {
println!("Command {cmd:?} not in task");
}
task.as_ref().borrow_mut().commands.add.retain(|c| {
debug!("'{:?}' != '{:?}' : {}", c, &cmd, *c != cmd);
*c != cmd
});
}
_ => unreachable!("Unknown action {:?}", action),
},
SetListType::Black => match action {
InputAction::Add => {
if task.as_ref().borrow().commands.sub.contains(&cmd) {
return Err("Command already exists".into());
}
task.as_ref().borrow_mut().commands.sub.push(cmd);
}
InputAction::Del => {
if !task.as_ref().borrow().commands.sub.contains(&cmd) {
println!("Command {cmd:?} not in task");
}
task.as_ref()
.borrow_mut()
.commands
.sub
.retain(|c| c != &cmd);
}
_ => unreachable!("Unknown action {:?}", action),
},
_ => unreachable!("Unknown setlist type"),
}
Ok(true)
}
pub fn cmd_setpolicy(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: &str,
task_id: IdTask,
cmd_policy: rootasrole_core::database::structs::SetBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr role r1 task t1 command setpolicy");
let task = rconfig.task(role_id, task_id)?;
task.as_ref()
.borrow_mut()
.commands
.default
.replace(cmd_policy);
Ok(true)
}
pub fn env_set_policylist(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_env: &IndexSet<EnvKey>,
options_env_policy: EnvBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o env set keep-only|delete-only {options_env:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().env = Some(SEnvOptions {
default_behavior: options_env_policy,
keep: if options_env_policy.is_delete() {
Some(options_env.clone())
} else {
None
},
delete: if options_env_policy.is_keep() {
Some(options_env.clone())
} else {
None
},
..Default::default()
});
Ok(())
})?;
Ok(true)
}
pub fn set_privileged(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_root: Option<rootasrole_core::database::options::SPrivileged>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o root set privileged {options_root:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().root = options_root;
Ok(())
})?;
Ok(true)
}
pub fn set_bounding(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_bounding: Option<rootasrole_core::database::options::SBounding>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o bounding set {options_bounding:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().bounding = options_bounding;
Ok(())
})?;
Ok(true)
}
pub fn set_authentication(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_auth: Option<rootasrole_core::database::options::SAuthentication>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o auth set {options_auth:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().authentication = options_auth;
Ok(())
})?;
Ok(true)
}
pub fn set_execinfo(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_execinfo: Option<rootasrole_core::database::options::SInfo>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o execinfo set {options_execinfo:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().execinfo = options_execinfo;
Ok(())
})?;
Ok(true)
}
pub fn set_umask(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_umask: Option<SUMask>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o umask set {options_umask:?}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().umask = options_umask;
Ok(())
})?;
Ok(true)
}
pub fn path_set(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
options_path: &str,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path set");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let path = binding.path.get_or_insert_default();
match setlist_type {
Some(SetListType::White) => {
path.add = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
Some(SetListType::Black) => {
path.sub = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
None => {
path.default_behavior = PathBehavior::Delete;
path.add = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
_ => unreachable!("Unknown setlist type"),
}
Ok(())
})?;
Ok(true)
}
pub fn path_purge(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path purge");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let path = binding.path.get_or_insert_default();
match setlist_type {
Some(SetListType::White) => {
if let Some(add) = &mut path.add {
add.clear();
}
}
Some(SetListType::Black) => {
if let Some(sub) = &mut path.sub {
sub.clear();
}
}
_ => unreachable!("Unknown setlist type"),
}
Ok(())
})?;
Ok(true)
}
pub fn workdir_purge(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o workdir purge");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let workdir_current = binding.workdir.take();
let mut workdir_set = match workdir_current {
Some(SWorkdirEither::Struct(workdir_set)) => workdir_set,
Some(SWorkdirEither::Path(path)) => SWorkdirSet {
fallback: Some(path),
..Default::default()
},
None => SWorkdirSet::default(),
};
match setlist_type {
Some(SetListType::White) => {
if let Some(add) = &mut workdir_set.add {
add.clear();
}
}
Some(SetListType::Black) => {
if let Some(sub) = &mut workdir_set.sub {
sub.clear();
}
}
_ => unreachable!("Unknown setlist type"),
}
binding.workdir = Some(SWorkdirEither::Struct(workdir_set));
Ok(())
})?;
Ok(true)
}
pub fn env_whitelist_set(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<&SetListType>,
options_env: &IndexSet<EnvKey>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o env whitelist set");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let env = binding.env.get_or_insert_default();
match setlist_type {
Some(SetListType::White) => {
env.keep = Some(options_env.clone());
}
Some(SetListType::Black) => {
env.delete = Some(options_env.clone());
}
Some(SetListType::Check) => {
env.check = Some(options_env.clone());
}
None => {
env.default_behavior = EnvBehavior::Delete;
env.keep = Some(options_env.clone());
}
_ => unreachable!("Unknown setlist type"),
}
Ok(())
})?;
Ok(true)
}
pub fn unset_timeout(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
timeout_arg: [bool; 3],
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o timeout unset");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut timeout = STimeout::default();
if timeout_arg[TimeoutOpt::Type as usize] {
timeout.type_field = None;
}
if timeout_arg[TimeoutOpt::Duration as usize] {
timeout.duration = None;
}
if timeout_arg[TimeoutOpt::MaxUsage as usize] {
timeout.max_usage = None;
}
if timeout_arg.iter().all(|b| *b) {
opt.as_ref().borrow_mut().timeout = None;
} else {
opt.as_ref().borrow_mut().timeout = Some(timeout);
}
Ok(())
})?;
Ok(true)
}
pub fn set_timeout(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
timeout_type: Option<rootasrole_core::database::options::TimestampType>,
timeout_duration: Option<SignedDuration>,
timeout_max_usage: Option<u64>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o timeout set");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut timeout = STimeout::default();
if let Some(timeout_type) = timeout_type {
timeout.type_field = Some(timeout_type);
}
if let Some(duration) = timeout_duration {
timeout.duration = Some(duration);
}
if let Some(max_usage) = timeout_max_usage {
timeout.max_usage = Some(max_usage);
}
opt.as_ref().borrow_mut().timeout = Some(timeout);
Ok(())
})?;
Ok(true)
}
pub fn path_setlist2(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
action: InputAction,
options_path: &str,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path set whitelist|blacklist add|del|set path1:path2:path3 22222222222");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut default_path = SPathOptions::default();
let mut binding = opt.as_ref().borrow_mut();
let path = binding.path.as_mut().unwrap_or(&mut default_path);
match setlist_type {
Some(SetListType::White) => match action {
InputAction::Add => {
path.add.get_or_insert_with(IndexSet::new).extend(
options_path
.split(':')
.map(std::string::ToString::to_string),
);
}
InputAction::Del => {
debug!("path.add del {:?}", path.add);
let hashset = options_path
.split(':')
.map(std::string::ToString::to_string)
.collect::<IndexSet<String>>();
if let Some(path) = &mut path.add {
*path = path
.difference(&hashset)
.cloned()
.collect::<IndexSet<String>>();
} else {
warn!("No path to remove from del list");
}
}
InputAction::Set => {
path.add = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
_ => unreachable!("Unknown action {:?}", action),
},
Some(SetListType::Black) => match action {
InputAction::Add => {
path.sub.get_or_insert_with(IndexSet::new).extend(
options_path
.split(':')
.map(std::string::ToString::to_string),
);
}
InputAction::Del => {
debug!("path.del del {:?}", path.sub);
let hashset = options_path
.split(':')
.map(std::string::ToString::to_string)
.collect::<IndexSet<String>>();
if let Some(path) = &mut path.sub {
*path = path
.difference(&hashset)
.cloned()
.collect::<IndexSet<String>>();
} else {
warn!("No path to remove from del list");
}
}
InputAction::Set => {
path.sub = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
_ => unreachable!("Unknown action {:?}", action),
},
_ => unreachable!("Unknown setlist type"),
}
Ok(())
})?;
Ok(true)
}
pub fn workdir_set_path(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_path: &str,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o workdir set path {options_path}");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
opt.as_ref().borrow_mut().workdir = Some(SWorkdirEither::Path(options_path.to_string()));
Ok(())
})?;
Ok(true)
}
pub fn workdir_setlist(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
action: InputAction,
options_path: &str,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o w set whitelist|blacklist add|del|set path1:path2:path3");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let workdir_current = binding.workdir.take();
let mut workdir_set = match workdir_current {
Some(SWorkdirEither::Struct(workdir_set)) => workdir_set,
Some(SWorkdirEither::Path(path)) => SWorkdirSet {
fallback: Some(path),
..Default::default()
},
None => SWorkdirSet::default(),
};
match setlist_type {
Some(SetListType::White) => match action {
InputAction::Add => {
workdir_set.add.get_or_insert_with(IndexSet::new).extend(
options_path
.split(':')
.map(std::string::ToString::to_string),
);
}
InputAction::Del => {
debug!("workdir.add del {:?}", workdir_set.add);
let hashset = options_path
.split(':')
.map(std::string::ToString::to_string)
.collect::<IndexSet<String>>();
if let Some(paths) = &mut workdir_set.add {
*paths = paths
.difference(&hashset)
.cloned()
.collect::<IndexSet<String>>();
} else {
warn!("No path to remove from del list");
}
}
InputAction::Set => {
workdir_set.add = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
_ => unreachable!("Unknown action {:?}", action),
},
Some(SetListType::Black) => match action {
InputAction::Add => {
workdir_set.sub.get_or_insert_with(IndexSet::new).extend(
options_path
.split(':')
.map(std::string::ToString::to_string),
);
}
InputAction::Del => {
debug!("workdir.del del {:?}", workdir_set.sub);
let hashset = options_path
.split(':')
.map(std::string::ToString::to_string)
.collect::<IndexSet<String>>();
if let Some(paths) = &mut workdir_set.sub {
*paths = paths
.difference(&hashset)
.cloned()
.collect::<IndexSet<String>>();
} else {
warn!("No path to remove from del list");
}
}
InputAction::Set => {
workdir_set.sub = Some(
options_path
.split(':')
.map(std::string::ToString::to_string)
.collect(),
);
}
_ => unreachable!("Unknown action {:?}", action),
},
_ => unreachable!("Unknown setlist type"),
}
binding.workdir = Some(SWorkdirEither::Struct(workdir_set));
Ok(())
})?;
Ok(true)
}
pub fn path_setpolicy(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_path_policy: PathBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path setpolicy delete-all");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
if let Some(path) = &mut opt.as_ref().borrow_mut().path {
path.default_behavior = options_path_policy;
} else {
opt.as_ref().borrow_mut().path = Some(SPathOptions {
default_behavior: options_path_policy,
..Default::default()
});
}
Ok(())
})
.map(|()| true)
}
pub fn workdir_setpolicy(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_workdir_policy: WorkdirBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path setpolicy delete-all");
perform_on_target_opt(rconfig, role_id, task_id, |opt: Rc<RefCell<Opt>>| {
let workdir = opt.as_ref().borrow_mut().workdir.as_mut().map_or_else(
|| {
SWorkdirEither::Struct(SWorkdirSet {
default_behavior: options_workdir_policy,
fallback: None,
add: None,
sub: None,
})
},
|workdir| match workdir {
SWorkdirEither::Path(p) => SWorkdirEither::Struct(SWorkdirSet {
default_behavior: options_workdir_policy,
fallback: Some(p.clone()),
add: None,
sub: None,
}),
SWorkdirEither::Struct(sworkdir_set) => {
sworkdir_set.default_behavior = options_workdir_policy;
SWorkdirEither::Struct(sworkdir_set.clone())
}
},
);
opt.as_ref().borrow_mut().workdir = Some(workdir);
Ok(())
})
.map(|()| true)
}
#[allow(clippy::too_many_lines)]
pub fn env_setlist_add(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
setlist_type: Option<SetListType>,
action: InputAction,
options_key_env: Option<IndexSet<EnvKey>>,
options_env_values: Option<HashMap<String, String>>,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o path {setlist_type:?} {action:?} path1 path2 path3");
perform_on_target_opt(rconfig, role_id, task_id, move |opt: Rc<RefCell<Opt>>| {
let mut default_env = SEnvOptions::default();
let mut binding = opt.as_ref().borrow_mut();
let env = binding.env.as_mut().unwrap_or(&mut default_env);
match setlist_type {
Some(SetListType::White) => match action {
InputAction::Add => {
env.keep
.get_or_insert_with(IndexSet::new)
.extend(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
InputAction::Del => {
if let Some(keep) = &mut env.keep {
*keep = keep
.difference(options_key_env.as_ref().ok_or("Empty list")?)
.cloned()
.collect::<IndexSet<EnvKey>>();
}
}
InputAction::Purge => {
env.keep = None;
}
InputAction::Set => {
env.keep
.replace(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
_ => unreachable!("Unknown action {:?}", action),
},
Some(SetListType::Black) => match action {
InputAction::Add => {
env.delete
.get_or_insert_with(IndexSet::new)
.extend(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
InputAction::Del => {
if let Some(delete) = &mut env.delete {
*delete = delete
.difference(options_key_env.as_ref().ok_or("Empty list")?)
.cloned()
.collect::<IndexSet<EnvKey>>();
}
}
InputAction::Purge => {
env.delete = None;
}
InputAction::Set => {
env.delete
.replace(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
_ => unreachable!("Unknown action {:?}", action),
},
Some(SetListType::Check) => match action {
InputAction::Add => {
env.check
.get_or_insert_with(IndexSet::new)
.extend(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
InputAction::Del => {
if let Some(check) = &mut env.check {
*check = check
.difference(options_key_env.as_ref().ok_or("Empty list")?)
.cloned()
.collect::<IndexSet<EnvKey>>();
}
}
InputAction::Set => {
env.check = Some(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
InputAction::Purge => {
env.check = None;
}
_ => unreachable!("Unknown action {:?}", action),
},
Some(SetListType::Set) => match action {
InputAction::Add => {
debug!("options_env_values: {options_env_values:?}");
env.set
.get_or_insert_default()
.extend(options_env_values.as_ref().ok_or("Empty list")?.clone());
}
InputAction::Del => {
debug!("options_env_values: {options_env_values:?}");
options_key_env
.as_ref()
.ok_or("Empty list")?
.into_iter()
.for_each(|k| {
if let Some(env) = &mut env.set {
env.remove(&k.to_string());
}
});
}
InputAction::Purge => {
debug!("options_env_values: {options_env_values:?}");
env.set = None;
}
InputAction::Set => {
debug!("options_env_values: {options_env_values:?}");
env.set
.replace(options_env_values.as_ref().ok_or("Empty list")?.clone());
}
_ => unreachable!("Unknown action {:?}", action),
},
None => match action {
InputAction::Set => {
env.keep
.replace(options_key_env.as_ref().ok_or("Empty list")?.clone());
}
_ => unreachable!("Unknown action {:?}", action),
},
}
Ok(())
})?;
Ok(true)
}
pub fn env_setpolicy(
rconfig: &Rc<RefCell<rootasrole_core::database::structs::SPolicy>>,
role_id: Option<&String>,
task_id: Option<IdTask>,
options_env_policy: EnvBehavior,
) -> Result<bool, Box<dyn Error>> {
debug!("chsr o env setpolicy delete-all {options_env_policy:?}");
perform_on_target_opt(rconfig, role_id, task_id, move |opt: Rc<RefCell<Opt>>| {
let mut binding = opt.as_ref().borrow_mut();
let env = binding.env.get_or_insert_default();
env.default_behavior = options_env_policy;
Ok(())
})?;
Ok(true)
}