1
0
mirror of https://github.com/uutils/coreutils synced 2024-07-08 19:56:10 +00:00

chcon: added implementation and integration tests

The ToDo list was updated to mark `chcon` as done.

Building and testing `chcon` requires enabling the `feat_selinux` feature. If `make` is used for building, then please specify `SELINUX_ENABLED=1` if building and testing on a system where SELinux is not enabled.
This commit is contained in:
Koutheir Attouchi 2021-08-05 00:39:37 -04:00
parent 63fd139b04
commit 090be5bb94
10 changed files with 1759 additions and 14 deletions

View File

@ -63,6 +63,7 @@ abspath
addprefix addprefix
addsuffix addsuffix
endef endef
findstring
firstword firstword
ifeq ifeq
ifneq ifneq
@ -89,5 +90,9 @@ markdownlint
rerast rerast
rollup rollup
sed sed
selinuxenabled
wslpath wslpath
xargs xargs
# * directories
sbin

View File

@ -106,6 +106,7 @@ whoami
# * vars/errno # * vars/errno
errno errno
EEXIST EEXIST
ENODATA
ENOENT ENOENT
ENOSYS ENOSYS
EPERM EPERM
@ -118,7 +119,9 @@ fcntl
vmsplice vmsplice
# * vars/libc # * vars/libc
COMFOLLOW
FILENO FILENO
FTSENT
HOSTSIZE HOSTSIZE
IDSIZE IDSIZE
IFBLK IFBLK
@ -151,6 +154,7 @@ SIGTERM
SYS_fdatasync SYS_fdatasync
SYS_syncfs SYS_syncfs
USERSIZE USERSIZE
accpath
addrinfo addrinfo
addrlen addrlen
blocksize blocksize
@ -174,15 +178,18 @@ inode
inodes inodes
isatty isatty
lchown lchown
pathlen
setgid setgid
setgroups setgroups
settime settime
setuid setuid
socktype socktype
statfs statfs
statp
statvfs statvfs
strcmp strcmp
strerror strerror
strlen
syncfs syncfs
umask umask
waitpid waitpid
@ -274,6 +281,13 @@ winerror
winnt winnt
winsock winsock
# * vars/selinux
freecon
getfilecon
lgetfilecon
lsetfilecon
setfilecon
# * vars/uucore # * vars/uucore
optflag optflag
optflagmulti optflagmulti

24
Cargo.lock generated
View File

@ -309,6 +309,7 @@ dependencies = [
"uu_base64", "uu_base64",
"uu_basename", "uu_basename",
"uu_cat", "uu_cat",
"uu_chcon",
"uu_chgrp", "uu_chgrp",
"uu_chmod", "uu_chmod",
"uu_chown", "uu_chown",
@ -697,6 +698,16 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "fts-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d31ec9f1580e270ee49a1fae7b102f54514142d9be2d4aa363c361363d65cac9"
dependencies = [
"bindgen",
"libc",
]
[[package]] [[package]]
name = "fuchsia-cprng" name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
@ -1972,6 +1983,19 @@ dependencies = [
"uucore_procs", "uucore_procs",
] ]
[[package]]
name = "uu_chcon"
version = "0.0.7"
dependencies = [
"clap",
"fts-sys",
"libc",
"selinux-sys",
"thiserror",
"uucore",
"uucore_procs",
]
[[package]] [[package]]
name = "uu_chgrp" name = "uu_chgrp"
version = "0.0.7" version = "0.0.7"

View File

@ -145,7 +145,7 @@ feat_os_unix_musl = [
# NOTE: # NOTE:
# The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time. # The selinux(-sys) crate requires `libselinux` headers and shared library to be accessible in the C toolchain at compile time.
# Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time. # Running a uutils compiled with `feat_selinux` requires an SELinux enabled Kernel at run time.
feat_selinux = ["id/selinux", "selinux"] feat_selinux = ["id/selinux", "selinux", "feat_require_selinux"]
## feature sets with requirements (restricting cross-platform availability) ## feature sets with requirements (restricting cross-platform availability)
# #
# ** NOTE: these `feat_require_...` sets should be minimized as much as possible to encourage cross-platform availability of utilities # ** NOTE: these `feat_require_...` sets should be minimized as much as possible to encourage cross-platform availability of utilities
@ -185,6 +185,10 @@ feat_require_unix_utmpx = [
"users", "users",
"who", "who",
] ]
# "feat_require_selinux" == set of utilities depending on SELinux.
feat_require_selinux = [
"chcon",
]
## (alternate/newer/smaller platforms) feature sets ## (alternate/newer/smaller platforms) feature sets
# "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: <https://fuchsia.dev>; <https://en.wikipedia.org/wiki/Google_Fuchsia>) # "feat_os_unix_fuchsia" == set of utilities which can be built/run on the "Fuchsia" OS (refs: <https://fuchsia.dev>; <https://en.wikipedia.org/wiki/Google_Fuchsia>)
feat_os_unix_fuchsia = [ feat_os_unix_fuchsia = [
@ -246,6 +250,7 @@ base32 = { optional=true, version="0.0.7", package="uu_base32", path="src/uu/b
base64 = { optional=true, version="0.0.7", package="uu_base64", path="src/uu/base64" } base64 = { optional=true, version="0.0.7", package="uu_base64", path="src/uu/base64" }
basename = { optional=true, version="0.0.7", package="uu_basename", path="src/uu/basename" } basename = { optional=true, version="0.0.7", package="uu_basename", path="src/uu/basename" }
cat = { optional=true, version="0.0.7", package="uu_cat", path="src/uu/cat" } cat = { optional=true, version="0.0.7", package="uu_cat", path="src/uu/cat" }
chcon = { optional=true, version="0.0.7", package="uu_chcon", path="src/uu/chcon" }
chgrp = { optional=true, version="0.0.7", package="uu_chgrp", path="src/uu/chgrp" } chgrp = { optional=true, version="0.0.7", package="uu_chgrp", path="src/uu/chgrp" }
chmod = { optional=true, version="0.0.7", package="uu_chmod", path="src/uu/chmod" } chmod = { optional=true, version="0.0.7", package="uu_chmod", path="src/uu/chmod" }
chown = { optional=true, version="0.0.7", package="uu_chown", path="src/uu/chown" } chown = { optional=true, version="0.0.7", package="uu_chown", path="src/uu/chown" }

View File

@ -46,6 +46,15 @@ BUSYBOX_ROOT := $(BASEDIR)/tmp
BUSYBOX_VER := 1.32.1 BUSYBOX_VER := 1.32.1
BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER) BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
ifeq ($(SELINUX_ENABLED),)
SELINUX_ENABLED := 0
ifneq ($(OS),Windows_NT)
ifeq ($(shell /sbin/selinuxenabled 2>/dev/null ; echo $$?),0)
SELINUX_ENABLED := 1
endif
endif
endif
# Possible programs # Possible programs
PROGS := \ PROGS := \
base32 \ base32 \
@ -147,10 +156,17 @@ UNIX_PROGS := \
users \ users \
who who
SELINUX_PROGS := \
chcon
ifneq ($(OS),Windows_NT) ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS) PROGS := $(PROGS) $(UNIX_PROGS)
endif endif
ifeq ($(SELINUX_ENABLED),1)
PROGS := $(PROGS) $(SELINUX_PROGS)
endif
UTILS ?= $(PROGS) UTILS ?= $(PROGS)
# Programs with usable tests # Programs with usable tests
@ -159,6 +175,7 @@ TEST_PROGS := \
base64 \ base64 \
basename \ basename \
cat \ cat \
chcon \
chgrp \ chgrp \
chmod \ chmod \
chown \ chown \
@ -228,6 +245,9 @@ TEST_SPEC_FEATURE :=
ifneq ($(SPEC),) ifneq ($(SPEC),)
TEST_NO_FAIL_FAST :=--no-fail-fast TEST_NO_FAIL_FAST :=--no-fail-fast
TEST_SPEC_FEATURE := test_unimplemented TEST_SPEC_FEATURE := test_unimplemented
else ifeq ($(SELINUX_ENABLED),1)
TEST_NO_FAIL_FAST :=
TEST_SPEC_FEATURE := feat_selinux
endif endif
define TEST_BUSYBOX define TEST_BUSYBOX

View File

@ -370,19 +370,20 @@ To contribute to uutils, please see [CONTRIBUTING](CONTRIBUTING.md).
| base64 | dd | stty | | base64 | dd | stty |
| basename | df | | | basename | df | |
| cat | expr | | | cat | expr | |
| chgrp | install | | | chcon | install | |
| chmod | join | | | chgrp | join | |
| chown | ls | | | chmod | ls | |
| chroot | more | | | chown | more | |
| cksum | numfmt | | | chroot | numfmt | |
| comm | od (`--strings` and 128-bit data types missing) | | cksum | od (`--strings` and 128-bit data types missing) | |
| csplit | pr | | | comm | pr | |
| cut | printf | | | csplit | printf | |
| dircolors | sort | | | cut | sort | |
| dirname | split | | | dircolors | split | |
| du | tac | | | dirname | tac | |
| echo | tail | | | du | tail | |
| env | test | | | echo | test | |
| env | | |
| expand | | | | expand | | |
| factor | | | | factor | | |
| false | | | | false | | |

27
src/uu/chcon/Cargo.toml Normal file
View File

@ -0,0 +1,27 @@
[package]
name = "uu_chcon"
version = "0.0.7"
authors = ["uutils developers"]
license = "MIT"
description = "chcon ~ (uutils) change file security context"
homepage = "https://github.com/uutils/coreutils"
repository = "https://github.com/uutils/coreutils/tree/master/src/uu/chcon"
keywords = ["coreutils", "uutils", "cli", "utility"]
categories = ["command-line-utilities"]
edition = "2018"
[lib]
path = "src/chcon.rs"
[dependencies]
clap = { version = "2.33", features = ["wrap_help"] }
uucore = { version = ">=0.0.9", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] }
uucore_procs = { version = ">=0.0.6", package="uucore_procs", path="../../uucore_procs" }
selinux-sys = { version = "0.5" }
fts-sys = { version = "0.2" }
thiserror = { version = "1.0" }
libc = { version = "0.2" }
[[bin]]
name = "chcon"
path = "src/main.rs"

1179
src/uu/chcon/src/chcon.rs Normal file

File diff suppressed because it is too large Load Diff

1
src/uu/chcon/src/main.rs Normal file
View File

@ -0,0 +1 @@
uucore_procs::main!(uu_chcon);

469
tests/by-util/test_chcon.rs Normal file
View File

@ -0,0 +1,469 @@
// spell-checker:ignore (jargon) xattributes
#![cfg(feature = "feat_selinux")]
use std::ffi::CString;
use std::path::Path;
use std::{io, iter, str};
use crate::common::util::*;
#[test]
fn version() {
new_ucmd!().arg("--version").succeeds();
new_ucmd!().arg("-V").succeeds();
}
#[test]
fn help() {
new_ucmd!().fails();
new_ucmd!().arg("--help").succeeds();
new_ucmd!().arg("-h").fails(); // -h is NOT --help, it is actually --no-dereference.
}
#[test]
fn reference_errors() {
for args in &[
&["--verbose", "--reference"] as &[&str],
&["--verbose", "--reference=/dev/null"],
&["--verbose", "--reference=/inexistent", "/dev/null"],
] {
new_ucmd!().args(args).fails();
}
}
#[test]
fn recursive_errors() {
for args in &[
&["--verbose", "-P"] as &[&str],
&["--verbose", "-H"],
&["--verbose", "-L"],
&["--verbose", "--recursive", "-P", "--dereference"],
&["--verbose", "--recursive", "-H", "--no-dereference"],
&["--verbose", "--recursive", "-L", "--no-dereference"],
] {
new_ucmd!().args(args).fails();
}
}
#[test]
fn valid_context() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
dir.symlink_file("a.tmp", "la.tmp");
let la_context = get_file_context(dir.plus("a.tmp")).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
cmd.args(&["--verbose", new_la_context])
.arg(dir.plus("la.tmp"))
.succeeds();
assert_eq!(get_file_context(dir.plus("la.tmp")).unwrap(), la_context);
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap().as_deref(),
Some(new_la_context)
);
}
#[test]
fn valid_context_on_valid_symlink() {
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 new_la_context = "guest_u:object_r:etc_t:s0:c42";
cmd.args(&["--verbose", "--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)
);
assert_eq!(get_file_context(dir.plus("a.tmp")).unwrap(), a_context);
}
#[test]
fn valid_context_on_broken_symlink() {
let (dir, mut cmd) = at_and_ucmd!();
dir.symlink_file("a.tmp", "la.tmp");
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
cmd.args(&["--verbose", "--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!();
dir.touch("a.tmp");
let a_context = get_file_context(dir.plus("a.tmp")).unwrap();
if a_context.is_none() {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
}
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
cmd.args(&["--verbose", new_la_context])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap().as_deref(),
Some(new_la_context)
);
}
#[test]
fn valid_context_directory() {
let (dir, mut cmd) = at_and_ucmd!();
dir.mkdir("a");
dir.symlink_dir("a", "la");
let b_path = Path::new("a").join("b.txt");
dir.touch(b_path.to_str().unwrap());
let la_context = get_file_context(dir.plus("la")).unwrap();
let b_context = get_file_context(dir.plus(b_path.to_str().unwrap())).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
cmd.args(&["--verbose", new_la_context])
.arg(dir.plus("la"))
.succeeds();
assert_eq!(get_file_context(dir.plus("la")).unwrap(), la_context);
assert_eq!(
get_file_context(dir.plus("a")).unwrap().as_deref(),
Some(new_la_context)
);
assert_eq!(
get_file_context(dir.plus(b_path.to_str().unwrap())).unwrap(),
b_context
);
}
#[test]
fn valid_context_directory_recursive() {
let (dir, mut cmd) = at_and_ucmd!();
dir.mkdir("a");
dir.symlink_dir("a", "la");
let b_path = Path::new("a").join("b.txt");
dir.touch(b_path.to_str().unwrap());
let a_context = get_file_context(dir.plus("a")).unwrap();
let b_context = get_file_context(dir.plus(b_path.to_str().unwrap())).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
// -P (default): do not traverse any symbolic links.
cmd.args(&["--verbose", "--recursive", new_la_context])
.arg(dir.plus("la"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("la")).unwrap().as_deref(),
Some(new_la_context)
);
assert_eq!(get_file_context(dir.plus("a")).unwrap(), a_context);
assert_eq!(
get_file_context(dir.plus(b_path.to_str().unwrap())).unwrap(),
b_context
);
}
#[test]
fn valid_context_directory_recursive_follow_args_dir_symlinks() {
let (dir, mut cmd) = at_and_ucmd!();
dir.mkdir("a");
dir.symlink_dir("a", "la");
let b_path = Path::new("a").join("b.txt");
dir.touch(b_path.to_str().unwrap());
let la_context = get_file_context(dir.plus("la")).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
/*
let lc_path = Path::new("a").join("lc");
dir.symlink_dir("c", lc_path.to_str().unwrap());
assert_eq!(
get_file_context(dir.plus(lc_path.to_str().unwrap())).unwrap(),
None
);
*/
// -H: if a command line argument is a symbolic link to a directory, traverse it.
cmd.args(&["--verbose", "--recursive", "-H", new_la_context])
.arg(dir.plus("la"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a")).unwrap().as_deref(),
Some(new_la_context)
);
assert_eq!(
get_file_context(dir.plus(b_path.to_str().unwrap()))
.unwrap()
.as_deref(),
Some(new_la_context)
);
assert_eq!(get_file_context(dir.plus("la")).unwrap(), la_context);
/*
assert_eq!(
get_file_context(dir.plus(lc_path.to_str().unwrap()))
.unwrap()
.as_deref(),
Some(new_la_context)
);
*/
}
#[test]
fn valid_context_directory_recursive_follow_all_symlinks() {
let (dir, mut cmd) = at_and_ucmd!();
dir.mkdir("a");
dir.symlink_dir("a", "la");
let b_path = Path::new("a").join("b.txt");
dir.touch(b_path.to_str().unwrap());
let c_path = Path::new("a").join("c");
dir.touch(c_path.to_str().unwrap());
let lc_path = Path::new("a").join("lc");
dir.symlink_dir(c_path.to_str().unwrap(), lc_path.to_str().unwrap());
let la_context = get_file_context(dir.plus("la")).unwrap();
let lc_context = get_file_context(dir.plus(lc_path.to_str().unwrap())).unwrap();
let new_la_context = "guest_u:object_r:etc_t:s0:c42";
// -L: traverse every symbolic link to a directory encountered.
cmd.args(&["--verbose", "--recursive", "-L", new_la_context])
.arg(dir.plus("la"))
.succeeds();
assert_eq!(get_file_context(dir.plus("la")).unwrap(), la_context);
assert_eq!(
get_file_context(dir.plus("a")).unwrap().as_deref(),
Some(new_la_context)
);
assert_eq!(
get_file_context(dir.plus(b_path.to_str().unwrap()))
.unwrap()
.as_deref(),
Some(new_la_context)
);
assert_eq!(
get_file_context(dir.plus(lc_path.to_str().unwrap())).unwrap(),
lc_context
);
assert_eq!(
get_file_context(dir.plus(c_path.to_str().unwrap()))
.unwrap()
.as_deref(),
Some(new_la_context)
);
}
#[test]
fn user_role_range_type() {
let (dir, mut cmd) = at_and_ucmd!();
dir.touch("a.tmp");
let a_context = get_file_context(dir.plus("a.tmp")).unwrap();
if a_context.is_none() {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
}
cmd.args(&[
"--verbose",
"--user=guest_u",
"--role=object_r",
"--type=etc_t",
"--range=s0:c42",
])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap().as_deref(),
Some("guest_u:object_r:etc_t:s0:c42")
);
}
#[test]
fn user_change() {
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=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!();
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[1] = "system_r";
components.join(":")
} else {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
String::from("unconfined_u:system_r:user_tmp_t:s0")
};
cmd.args(&["--verbose", "--role=system_r"])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap(),
Some(new_a_context)
);
}
#[test]
fn type_change() {
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[2] = "etc_t";
components.join(":")
} else {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
String::from("unconfined_u:object_r:etc_t:s0")
};
cmd.args(&["--verbose", "--type=etc_t"])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap(),
Some(new_a_context)
);
}
#[test]
fn range_change() {
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 {
a_context
.split(':')
.take(3)
.chain(iter::once("s0:c42"))
.collect::<Vec<_>>()
.join(":")
} else {
set_file_context(dir.plus("a.tmp"), "unconfined_u:object_r:user_tmp_t:s0").unwrap();
String::from("unconfined_u:object_r:user_tmp_t:s0:c42")
};
cmd.args(&["--verbose", "--range=s0:c42"])
.arg(dir.plus("a.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("a.tmp")).unwrap(),
Some(new_a_context)
);
}
#[test]
fn valid_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("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("a.tmp")))
.arg(dir.plus("b.tmp"))
.succeeds();
assert_eq!(
get_file_context(dir.plus("b.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) {
Err(r) => {
println!("get_file_context failed: '{}': {}.", path.display(), &r);
Err(r)
}
Ok(None) => {
println!(
"get_file_context: '{}': No SELinux context defined.",
path.display()
);
Ok(None)
}
Ok(Some(context)) => {
let bytes = context
.as_bytes()
.splitn(2, |&b| b == 0_u8)
.next()
.unwrap_or_default();
let context = String::from_utf8(bytes.into()).unwrap_or_default();
println!("get_file_context: '{}' => '{}'.", context, path.display());
Ok(Some(context))
}
}
}
fn set_file_context(path: impl AsRef<Path>, context: &str) -> Result<(), selinux::errors::Error> {
let c_context = CString::new(context.as_bytes()).map_err(|_r| selinux::errors::Error::IO {
source: io::Error::from(io::ErrorKind::InvalidInput),
operation: "CString::new",
})?;
let path = path.as_ref();
let r =
selinux::SecurityContext::from_c_str(&c_context, false).set_for_path(path, false, false);
if let Err(r) = &r {
println!(
"set_file_context failed: '{}' => '{}': {}.",
context,
path.display(),
r
)
} else {
println!("set_file_context: '{}' => '{}'.", context, path.display())
}
r
}