Skip to content

Commit

Permalink
Migrate adjusting RCC binary and profile permissions to new setup API
Browse files Browse the repository at this point in the history
CMK-20276
  • Loading branch information
jherbel committed Nov 20, 2024
1 parent 0f10f2a commit 3a2e989
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 111 deletions.
132 changes: 120 additions & 12 deletions src/bin/scheduler/setup/rcc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
use super::api::{self, run_steps};
#[cfg(windows)]
use super::api::{skip, SetupStep, StepWithPlans};
use super::plans_by_sessions;
#[cfg(windows)]
use super::windows_permissions::run_icacls_command;
use crate::internal_config::{sort_plans_by_grouping, GlobalConfig, Plan};
use crate::logging::log_and_return_error;
#[cfg(windows)]
Expand All @@ -18,7 +23,9 @@ pub fn setup(
global_config: &GlobalConfig,
plans: Vec<Plan>,
) -> Result<(Vec<Plan>, Vec<SetupFailure>), Cancelled> {
let (rcc_plans, mut system_plans): (Vec<Plan>, Vec<Plan>) = plans
let (surviving_plans, failures) = run_setup_steps(global_config, plans);

let (rcc_plans, mut system_plans): (Vec<Plan>, Vec<Plan>) = surviving_plans
.into_iter()
.partition(|plan| matches!(plan.environment, Environment::Rcc(_)));

Expand All @@ -27,24 +34,15 @@ pub fn setup(
return Ok((system_plans, vec![]));
}

#[cfg(windows)]
let (surviving_rcc_plans, rcc_file_permissions_failures) = {
use super::windows_permissions::adjust_rcc_file_permissions;
adjust_rcc_file_permissions(&global_config.rcc_config, rcc_plans)
};
#[cfg(unix)]
let (surviving_rcc_plans, rcc_file_permissions_failures) = (rcc_plans, vec![]);

let (surviving_rcc_plans, further_rcc_setup_failures) =
rcc_setup(global_config, surviving_rcc_plans)?;
let (surviving_rcc_plans, further_rcc_setup_failures) = rcc_setup(global_config, rcc_plans)?;

let mut surviving_plans = vec![];
surviving_plans.extend(surviving_rcc_plans);
surviving_plans.extend(system_plans);
sort_plans_by_grouping(&mut surviving_plans);
Ok((
surviving_plans,
rcc_file_permissions_failures
failures
.into_iter()
.chain(further_rcc_setup_failures)
.collect(),
Expand All @@ -55,6 +53,116 @@ pub fn rcc_setup_working_directory(working_directory: &Utf8Path) -> Utf8PathBuf
working_directory.join("rcc_setup")
}

fn run_setup_steps(config: &GlobalConfig, mut plans: Vec<Plan>) -> (Vec<Plan>, Vec<SetupFailure>) {
// needed to avoid clippy::type_complexity below
type Gatherer = fn(&GlobalConfig, Vec<Plan>) -> Vec<(Box<dyn api::SetupStep>, Vec<Plan>)>;
let gather_requirements: Vec<Gatherer> = vec![
#[cfg(windows)]
gather_rcc_binary_permissions,
#[cfg(windows)]
gather_rcc_profile_permissions,
];

let mut failures = Vec::new();
for gather in gather_requirements.iter() {
plans = {
let plan_count = plans.len();
let setup_steps = gather(config, plans);
assert_eq!(
plan_count,
setup_steps.iter().map(|s| s.1.len()).sum::<usize>()
);
let (surviving_plans, current_errors) = run_steps(setup_steps);
failures.extend(current_errors);
surviving_plans
};
}
sort_plans_by_grouping(&mut plans);
(plans, failures)
}

#[cfg(windows)]
struct StepFilePermissions {
target: Utf8PathBuf,
session: Session,
icacls_permissions: String,
}

#[cfg(windows)]
impl SetupStep for StepFilePermissions {
fn setup(&self) -> Result<(), api::Error> {
if let Session::User(user_session) = &self.session {
log::info!(
"Granting user `{user}` {permissions} access to {target}.",
user = &user_session.user_name,
permissions = &self.icacls_permissions,
target = &self.target,
);
run_icacls_command([
self.target.as_str(),
"/grant",
&format!("{}:{}", &user_session.user_name, self.icacls_permissions),
])
.map_err(|err| {
api::Error::new(
format!(
"Adjusting permissions of {} for user `{}` failed",
self.target, &user_session.user_name
),
err,
)
})?;
}
Ok(())
}
}

#[cfg(windows)]
fn gather_rcc_binary_permissions(config: &GlobalConfig, plans: Vec<Plan>) -> Vec<StepWithPlans> {
let (rcc_plans, system_plans): (Vec<Plan>, Vec<Plan>) = plans
.into_iter()
.partition(|plan| matches!(plan.environment, Environment::Rcc(_)));
let mut steps: Vec<StepWithPlans> = Vec::new();
for (session, plans_in_session) in plans_by_sessions(rcc_plans) {
steps.push((
Box::new(StepFilePermissions {
target: config.rcc_config.binary_path.clone(),
session,
icacls_permissions: "(RX)".to_string(),
}),
plans_in_session,
));
}
steps.push(skip(system_plans));
steps
}

#[cfg(windows)]
fn gather_rcc_profile_permissions(config: &GlobalConfig, plans: Vec<Plan>) -> Vec<StepWithPlans> {
let (rcc_plans, system_plans): (Vec<Plan>, Vec<Plan>) = plans
.into_iter()
.partition(|plan| matches!(plan.environment, Environment::Rcc(_)));
let mut steps: Vec<StepWithPlans> = Vec::new();

match &config.rcc_config.profile_config {
RCCProfileConfig::Default => steps.push(skip(rcc_plans)),
RCCProfileConfig::Custom(custom_profile) => {
for (session, plans_in_session) in plans_by_sessions(rcc_plans) {
steps.push((
Box::new(StepFilePermissions {
target: custom_profile.path.clone(),
session,
icacls_permissions: "(R)".to_string(),
}),
plans_in_session,
));
}
}
}
steps.push(skip(system_plans));
steps
}

fn rcc_setup(
global_config: &GlobalConfig,
rcc_plans: Vec<Plan>,
Expand Down
102 changes: 3 additions & 99 deletions src/bin/scheduler/setup/windows_permissions.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,10 @@
#![cfg(windows)]
use super::plans_by_sessions;
use anyhow::{bail, Context};
use log::{debug, error};
use std::process::Command;

use crate::internal_config::Plan;
use camino::Utf8Path;
use robotmk::config::{RCCConfig, RCCProfileConfig};
use robotmk::results::SetupFailure;
use robotmk::session::Session;

pub fn grant_permissions_to_all_plan_users(
path: &Utf8Path,
plans: Vec<Plan>,
permissions: &str,
additional_icacls_args: &[&str],
description_for_failure_reporting: &str,
) -> (Vec<Plan>, Vec<SetupFailure>) {
let mut surviving_plans = vec![];
let mut failures = vec![];

for (session, plans_in_session) in plans_by_sessions(plans) {
if let Session::User(user_session) = session {
let icacls_permission_arg = format!("{}:{}", user_session.user_name, permissions);
let mut icacls_args = vec![path.as_str(), "/grant", &icacls_permission_arg];
icacls_args.extend(additional_icacls_args);

match run_icacls_command(icacls_args).context(format!(
"Adjusting permissions of {path} for user `{}` failed",
user_session.user_name
)) {
Ok(_) => surviving_plans.extend(plans_in_session),
Err(error) => {
for plan in plans_in_session {
error!(
"Plan {}: Failed to adjust permissions of \
{description_for_failure_reporting} for plan user. Plan won't be scheduled.
Error: {error:?}",
plan.id
);
failures.push(SetupFailure {
plan_id: plan.id.clone(),
summary: format!(
"Failed to adjust permissions of {description_for_failure_reporting} for plan user"
),
details: format!("{error:?}"),
});
}
}
}
} else {
surviving_plans.extend(plans_in_session);
}
}
use std::process::Command;

(surviving_plans, failures)
pub fn run_icacls_command<'a>(arguments: impl IntoIterator<Item = &'a str>) -> anyhow::Result<()> {
run_command("icacls.exe", arguments)
}

pub fn grant_full_access(user: &str, target_path: &Utf8Path) -> anyhow::Result<()> {
Expand All @@ -78,48 +28,6 @@ pub fn reset_access(target_path: &Utf8Path) -> anyhow::Result<()> {
})
}

pub fn adjust_rcc_file_permissions(
rcc_config: &RCCConfig,
rcc_plans: Vec<Plan>,
) -> (Vec<Plan>, Vec<SetupFailure>) {
debug!(
"Granting all plan users read and execute access to {}",
rcc_config.binary_path
);
let (mut surviving_rcc_plans, rcc_binary_permissions_failures) =
grant_permissions_to_all_plan_users(
&rcc_config.binary_path,
rcc_plans,
"(RX)",
&[],
"RCC binary",
);

let mut rcc_profile_file_permissions_failures = vec![];
if let RCCProfileConfig::Custom(custom_rcc_profile_config) = &rcc_config.profile_config {
debug!(
"Granting all plan users read access to {}",
custom_rcc_profile_config.path
);
(surviving_rcc_plans, rcc_profile_file_permissions_failures) =
grant_permissions_to_all_plan_users(
&custom_rcc_profile_config.path,
surviving_rcc_plans,
"(R)",
&[],
"RCC profile file",
);
}

(
surviving_rcc_plans,
rcc_binary_permissions_failures
.into_iter()
.chain(rcc_profile_file_permissions_failures)
.collect(),
)
}

pub fn transfer_directory_ownership_to_admin_group_recursive(
target_path: &Utf8Path,
) -> anyhow::Result<()> {
Expand Down Expand Up @@ -149,10 +57,6 @@ fn run_command<'a>(
Ok(())
}

fn run_icacls_command<'a>(arguments: impl IntoIterator<Item = &'a str>) -> anyhow::Result<()> {
run_command("icacls.exe", arguments)
}

fn run_takeown_command<'a>(arguments: impl IntoIterator<Item = &'a str>) -> anyhow::Result<()> {
run_command("takeown.exe", arguments)
}

0 comments on commit 3a2e989

Please sign in to comment.