1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

selinux: add function get_selinux_security_context to uucore

Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
Sylvestre Ledru 2025-04-13 20:47:25 +02:00
parent efb09204a2
commit 8220f061ef

View file

@ -10,6 +10,20 @@ use selinux::SecurityContext;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
SELinuxNotEnabled, SELinuxNotEnabled,
FileOpenFailure,
ContextRetrievalFailure,
ContextConversionFailure,
}
impl From<Error> for i32 {
fn from(error: Error) -> i32 {
match error {
Error::SELinuxNotEnabled => 1,
Error::FileOpenFailure => 2,
Error::ContextRetrievalFailure => 3,
Error::ContextConversionFailure => 4,
}
}
} }
/// Checks if SELinux is enabled on the system. /// Checks if SELinux is enabled on the system.
@ -109,6 +123,73 @@ pub fn set_selinux_security_context(path: &Path, context: Option<&String>) -> Re
} }
} }
/// Gets the SELinux security context for the given filesystem path.
///
/// Retrieves the security context of the specified filesystem path if SELinux is enabled
/// on the system.
///
/// # Arguments
///
/// * `path` - Filesystem path for which to retrieve the SELinux context.
///
/// # Returns
///
/// * `Ok(String)` - The SELinux context string if successfully retrieved. Returns an empty
/// string if no context was found.
/// * `Err(Error)` - An error variant indicating the type of failure:
/// - `Error::SELinuxNotEnabled` - SELinux is not enabled on the system.
/// - `Error::FileOpenFailure` - Failed to open the specified file.
/// - `Error::ContextRetrievalFailure` - Failed to retrieve the security context.
/// - `Error::ContextConversionFailure` - Failed to convert the security context to a string.
///
/// # Examples
///
/// ```
/// use std::path::Path;
/// use uucore::selinux::{get_selinux_security_context, Error};
///
/// // Get the SELinux context for a file
/// match get_selinux_security_context(Path::new("/path/to/file")) {
/// Ok(context) => {
/// if context.is_empty() {
/// println!("No SELinux context found for the file");
/// } else {
/// println!("SELinux context: {}", context);
/// }
/// },
/// Err(Error::SELinuxNotEnabled) => println!("SELinux is not enabled on this system"),
/// Err(Error::FileOpenFailure) => println!("Failed to open the file"),
/// Err(Error::ContextRetrievalFailure) => println!("Failed to retrieve the security context"),
/// Err(Error::ContextConversionFailure) => println!("Failed to convert the security context to a string"),
/// }
/// ```
pub fn get_selinux_security_context(path: &Path) -> Result<String, Error> {
if selinux::kernel_support() == selinux::KernelSupport::Unsupported {
return Err(Error::SELinuxNotEnabled);
}
let f = std::fs::File::open(path).map_err(|_| Error::FileOpenFailure)?;
// Get the security context of the file
let context = match SecurityContext::of_file(&f, false) {
Ok(Some(ctx)) => ctx,
Ok(None) => return Ok(String::new()), // No context found, return empty string
Err(_) => return Err(Error::ContextRetrievalFailure),
};
let context_c_string = context
.to_c_string()
.map_err(|_| Error::ContextConversionFailure)?;
if let Some(c_str) = context_c_string {
// Convert the C string to a Rust String
Ok(c_str.to_string_lossy().to_string())
} else {
Ok(String::new())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -171,4 +252,43 @@ mod tests {
} }
} }
} }
#[test]
fn test_get_selinux_security_context() {
let tmpfile = NamedTempFile::new().expect("Failed to create tempfile");
let path = tmpfile.path();
std::fs::write(path, b"test content").expect("Failed to write to tempfile");
let result = get_selinux_security_context(path);
if result.is_ok() {
println!("Retrieved SELinux context: {}", result.unwrap());
} else {
let err = result.unwrap_err();
// Valid error types
match err {
Error::SELinuxNotEnabled => assert!(true, "SELinux not supported"),
Error::ContextRetrievalFailure => assert!(true, "Context retrieval failure"),
Error::ContextConversionFailure => assert!(true, "Context conversion failure"),
Error::FileOpenFailure => {
panic!("File open failure occurred despite file being created")
}
}
}
}
#[test]
fn test_get_selinux_context_nonexistent_file() {
let path = Path::new("/nonexistent/file/that/does/not/exist");
let result = get_selinux_security_context(path);
assert!(result.is_err());
assert!(
matches!(result.unwrap_err(), Error::FileOpenFailure),
"Expected file open error for nonexistent file"
);
}
} }