chcon: allow repeated flags and arguments

This commit is contained in:
Ben Wiederhake 2024-03-02 01:35:45 +01:00 committed by Sylvestre Ledru
parent dbfd4d80ee
commit 8be5f7a89d
2 changed files with 119 additions and 1 deletions

View file

@ -154,6 +154,7 @@ pub fn uu_app() -> Command {
.override_usage(format_usage(USAGE))
.infer_long_args(true)
.disable_help_flag(true)
.args_override_self(true)
.arg(
Arg::new(options::HELP)
.long(options::HELP)
@ -180,7 +181,7 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(options::preserve_root::PRESERVE_ROOT)
.long(options::preserve_root::PRESERVE_ROOT)
.conflicts_with(options::preserve_root::NO_PRESERVE_ROOT)
.overrides_with(options::preserve_root::NO_PRESERVE_ROOT)
.help("Fail to operate recursively on '/'.")
.action(ArgAction::SetTrue),
)

View file

@ -374,6 +374,30 @@ fn user_change() {
);
}
#[test]
fn user_change_repeated() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
let a_context = get_file_context(dir.plus("a.tmp")).unwrap();
let new_a_context = if let Some(a_context) = a_context {
let mut components: Vec<_> = a_context.split(':').collect();
components[0] = "guest_u";
components.join(":")
} else {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
String::from("guest_u:object_r:user_tmp_t:s0")
};
cmd.args(&["--verbose", "--user=wrong", "--user=guest_u"])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap(),
Some(new_a_context)
);
}
#[test]
fn role_change() {
let (dir, mut cmd) = at_and_ucmd!();
@ -471,6 +495,99 @@ fn valid_reference() {
);
}
#[test]
fn valid_reference_repeat_flags() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
let new_a_context = "guest_u:object_r:etc_t:s0:c42";
set_file_context(dir.plus("a.tmp"), new_a_context).unwrap();
dir.touch("b.tmp");
let b_context = get_file_context(dir.plus("b.tmp")).unwrap();
assert_ne!(b_context.as_deref(), Some(new_a_context));
cmd.arg("--verbose")
.arg("-vvRRHHLLPP") // spell-checker:disable-line
.arg("--no-preserve-root")
.arg("--no-preserve-root")
.arg("--preserve-root")
.arg("--preserve-root")
.arg("--dereference")
.arg("--dereference")
.arg("--no-dereference")
.arg("--no-dereference")
.arg(format!("--reference={}", dir.plus_as_string("a.tmp")))
.arg(dir.plus("b.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("b.tmp")).unwrap().as_deref(),
Some(new_a_context)
);
}
#[test]
fn valid_reference_repeated_reference() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
let new_a_context = "guest_u:object_r:etc_t:s0:c42";
set_file_context(dir.plus("a.tmp"), new_a_context).unwrap();
dir.touch("wrong.tmp");
let new_wrong_context = "guest_u:object_r:etc_t:s42:c0";
set_file_context(dir.plus("wrong.tmp"), new_wrong_context).unwrap();
dir.touch("b.tmp");
let b_context = get_file_context(dir.plus("b.tmp")).unwrap();
assert_ne!(b_context.as_deref(), Some(new_a_context));
cmd.arg("--verbose")
.arg(format!("--reference={}", dir.plus_as_string("wrong.tmp")))
.arg(format!("--reference={}", dir.plus_as_string("a.tmp")))
.arg(dir.plus("b.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("b.tmp")).unwrap().as_deref(),
Some(new_a_context)
);
assert_eq!(
get_file_context(dir.plus("wrong.tmp")).unwrap().as_deref(),
Some(new_wrong_context)
);
}
#[test]
fn valid_reference_multi() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
let new_a_context = "guest_u:object_r:etc_t:s0:c42";
set_file_context(dir.plus("a.tmp"), new_a_context).unwrap();
dir.touch("b1.tmp");
let b1_context = get_file_context(dir.plus("b1.tmp")).unwrap();
assert_ne!(b1_context.as_deref(), Some(new_a_context));
dir.touch("b2.tmp");
let b2_context = get_file_context(dir.plus("b2.tmp")).unwrap();
assert_ne!(b2_context.as_deref(), Some(new_a_context));
cmd.arg("--verbose")
.arg(format!("--reference={}", dir.plus_as_string("a.tmp")))
.arg(dir.plus("b1.tmp"))
.arg(dir.plus("b2.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("b1.tmp")).unwrap().as_deref(),
Some(new_a_context)
);
assert_eq!(
get_file_context(dir.plus("b2.tmp")).unwrap().as_deref(),
Some(new_a_context)
);
}
fn get_file_context(path: impl AsRef<Path>) -> Result<Option<String>, selinux::errors::Error> {
let path = path.as_ref();
match selinux::SecurityContext::of_path(path, false, false) {