1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge pull request #6039 from BenWiederhake/dev-chcon-repeat-args

chcon: Handle repeated flags and overrides between --no-XXX and --XXX
This commit is contained in:
Sylvestre Ledru 2024-03-10 22:36:57 +01:00 committed by GitHub
commit 2e8f0e501c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 170 additions and 2 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)
@ -163,7 +164,7 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(options::dereference::DEREFERENCE)
.long(options::dereference::DEREFERENCE)
.conflicts_with(options::dereference::NO_DEREFERENCE)
.overrides_with(options::dereference::NO_DEREFERENCE)
.help(
"Affect the referent of each symbolic link (this is the default), \
rather than the symbolic link itself.",
@ -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

@ -88,6 +88,33 @@ fn valid_context_on_valid_symlink() {
assert_eq!(get_file_context(dir.plus("a.tmp")).unwrap(), a_context);
}
#[test]
fn valid_context_on_valid_symlink_override_dereference() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
dir.symlink_file("a.tmp", "la.tmp");
let a_context = get_file_context(dir.plus("a.tmp")).unwrap();
let la_context = get_file_context(dir.plus("la.tmp")).unwrap();
let new_a_context = "guest_u:object_r:etc_t:s0:c42";
assert_ne!(a_context.as_deref(), Some(new_a_context));
assert_ne!(la_context.as_deref(), Some(new_a_context));
cmd.args(&[
"--verbose",
"--no-dereference",
"--dereference",
new_a_context,
])
.arg(dir.plus("la.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap().as_deref(),
Some(new_a_context)
);
assert_eq!(get_file_context(dir.plus("la.tmp")).unwrap(), la_context);
}
#[test]
fn valid_context_on_broken_symlink() {
let (dir, mut cmd) = at_and_ucmd!();
@ -104,6 +131,29 @@ fn valid_context_on_broken_symlink() {
);
}
#[test]
fn valid_context_on_broken_symlink_after_deref() {
let (dir, mut cmd) = at_and_ucmd!();
dir.symlink_file("a.tmp", "la.tmp");
let la_context = get_file_context(dir.plus("la.tmp")).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
assert_ne!(la_context.as_deref(), Some(new_la_context));
cmd.args(&[
"--verbose",
"--dereference",
"--no-dereference",
new_la_context,
])
.arg(dir.plus("la.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("la.tmp")).unwrap().as_deref(),
Some(new_la_context)
);
}
#[test]
fn valid_context_with_prior_xattributes() {
let (dir, mut cmd) = at_and_ucmd!();
@ -324,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!();
@ -421,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) {