Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/uu/runcon/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,31 @@ runcon-after-help = Run COMMAND with completely-specified CONTEXT, or with curre
Note that only carefully-chosen contexts are likely to successfully run.

If neither CONTEXT nor COMMAND is specified, the current security context is printed.

# Help messages
runcon-help-compute = Compute process transition context before modifying.
runcon-help-user = Set user USER in the target security context.
runcon-help-role = Set role ROLE in the target security context.
runcon-help-type = Set type TYPE in the target security context.
runcon-help-range = Set range RANGE in the target security context.

# Error messages
runcon-error-no-command = No command is specified
runcon-error-selinux-not-enabled = runcon may be used only on a SELinux kernel
runcon-error-operation-failed = { $operation } failed
runcon-error-operation-failed-on = { $operation } failed on { $operand }

# Operation names
runcon-operation-getting-current-context = Getting security context of the current process
runcon-operation-creating-context = Creating new context
runcon-operation-checking-context = Checking security context
runcon-operation-setting-context = Setting new security context
runcon-operation-getting-process-class = Getting process security class
runcon-operation-getting-file-context = Getting security context of command file
runcon-operation-computing-transition = Computing result of process transition
runcon-operation-getting-context = Getting security context
runcon-operation-setting-user = Setting security context user
runcon-operation-setting-role = Setting security context role
runcon-operation-setting-type = Setting security context type
runcon-operation-setting-range = Setting security context range
runcon-operation-executing-command = Executing command
38 changes: 38 additions & 0 deletions src/uu/runcon/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
runcon-about = Exécuter une commande avec le contexte de sécurité spécifié sous les systèmes avec SELinux activé.
runcon-usage = runcon CONTEXTE COMMANDE [ARG...]
runcon [-c] [-u UTILISATEUR] [-r RÔLE] [-t TYPE] [-l PLAGE] COMMANDE [ARG...]
runcon-after-help = Exécuter COMMANDE avec un CONTEXTE complètement spécifié, ou avec le contexte de sécurité actuel ou de transition modifié par un ou plusieurs parmi NIVEAU, RÔLE, TYPE et UTILISATEUR.

Si aucun de --compute, --type, --user, --role ou --range n'est spécifié, alors le premier argument est utilisé comme contexte complet.

Notez que seuls les contextes soigneusement choisis ont des chances de s'exécuter avec succès.

Si ni CONTEXTE ni COMMANDE n'est spécifié, le contexte de sécurité actuel est affiché.

# Messages d'aide
runcon-help-compute = Calculer le contexte de transition de processus avant modification.
runcon-help-user = Définir l'utilisateur UTILISATEUR dans le contexte de sécurité cible.
runcon-help-role = Définir le rôle RÔLE dans le contexte de sécurité cible.
runcon-help-type = Définir le type TYPE dans le contexte de sécurité cible.
runcon-help-range = Définir la plage PLAGE dans le contexte de sécurité cible.

# Messages d'erreur
runcon-error-no-command = Aucune commande n'est spécifiée
runcon-error-selinux-not-enabled = runcon ne peut être utilisé que sur un noyau SELinux
runcon-error-operation-failed = { $operation } a échoué
runcon-error-operation-failed-on = { $operation } a échoué sur { $operand }

# Noms d'opération
runcon-operation-getting-current-context = Obtention du contexte de sécurité du processus actuel
runcon-operation-creating-context = Création d'un nouveau contexte
runcon-operation-checking-context = Vérification du contexte de sécurité
runcon-operation-setting-context = Définition du nouveau contexte de sécurité
runcon-operation-getting-process-class = Obtention de la classe de sécurité du processus
runcon-operation-getting-file-context = Obtention du contexte de sécurité du fichier de commande
runcon-operation-computing-transition = Calcul du résultat de la transition de processus
runcon-operation-getting-context = Obtention du contexte de sécurité
runcon-operation-setting-user = Définition de l'utilisateur du contexte de sécurité
runcon-operation-setting-role = Définition du rôle du contexte de sécurité
runcon-operation-setting-type = Définition du type du contexte de sécurité
runcon-operation-setting-range = Définition de la plage du contexte de sécurité
runcon-operation-executing-command = Exécution de la commande
12 changes: 7 additions & 5 deletions src/uu/runcon/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
// file that was distributed with this source code.
#![cfg(target_os = "linux")]

use std::collections::HashMap;
use std::ffi::OsString;
use std::fmt::{Display, Formatter, Write};
use std::io;
use std::str::Utf8Error;

use uucore::display::Quotable;
use uucore::error::UError;
use uucore::locale::{get_message, get_message_with_args};

pub(crate) type Result<T> = std::result::Result<T, Error>;

Expand All @@ -25,10 +27,10 @@ pub(crate) mod error_exit_status {

#[derive(thiserror::Error, Debug)]
pub(crate) enum Error {
#[error("No command is specified")]
#[error("{}", get_message("runcon-error-no-command"))]
MissingCommand,

#[error("runcon may be used only on a SELinux kernel")]
#[error("{}", get_message("runcon-error-selinux-not-enabled"))]
SELinuxNotEnabled,

#[error(transparent)]
Expand All @@ -37,19 +39,19 @@ pub(crate) enum Error {
#[error(transparent)]
CommandLine(#[from] clap::Error),

#[error("{operation} failed")]
#[error("{}", get_message_with_args("runcon-error-operation-failed", HashMap::from([("operation".to_string(), get_message(.operation))])))]
SELinux {
operation: &'static str,
source: selinux::errors::Error,
},

#[error("{operation} failed")]
#[error("{}", get_message_with_args("runcon-error-operation-failed", HashMap::from([("operation".to_string(), get_message(.operation))])))]
Io {
operation: &'static str,
source: io::Error,
},

#[error("{operation} failed on {}", .operand1.quote())]
#[error("{}", get_message_with_args("runcon-error-operation-failed-on", HashMap::from([("operation".to_string(), get_message(.operation)), ("operand".to_string(), .operand1.quote().to_string())])))]
Io1 {
operation: &'static str,
operand1: OsString,
Expand Down
76 changes: 42 additions & 34 deletions src/uu/runcon/src/runcon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

use clap::builder::ValueParser;
use uucore::error::{UClapError, UError, UResult};
use uucore::locale::get_message;

use clap::{Arg, ArgAction, Command};
use selinux::{OpaqueSecurityContext, SecurityClass, SecurityContext};
Expand All @@ -23,8 +24,6 @@ mod errors;
use errors::error_exit_status;
use errors::{Error, Result, RunconError};

use uucore::locale::get_message;

pub mod options {
pub const COMPUTE: &str = "compute";

Expand Down Expand Up @@ -96,39 +95,39 @@ pub fn uu_app() -> Command {
Arg::new(options::COMPUTE)
.short('c')
.long(options::COMPUTE)
.help("Compute process transition context before modifying.")
.help(get_message("runcon-help-compute"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::USER)
.short('u')
.long(options::USER)
.value_name("USER")
.help("Set user USER in the target security context.")
.help(get_message("runcon-help-user"))
.value_parser(ValueParser::os_string()),
)
.arg(
Arg::new(options::ROLE)
.short('r')
.long(options::ROLE)
.value_name("ROLE")
.help("Set role ROLE in the target security context.")
.help(get_message("runcon-help-role"))
.value_parser(ValueParser::os_string()),
)
.arg(
Arg::new(options::TYPE)
.short('t')
.long(options::TYPE)
.value_name("TYPE")
.help("Set type TYPE in the target security context.")
.help(get_message("runcon-help-type"))
.value_parser(ValueParser::os_string()),
)
.arg(
Arg::new(options::RANGE)
.short('l')
.long(options::RANGE)
.value_name("RANGE")
.help("Set range RANGE in the target security context.")
.help(get_message("runcon-help-range"))
.value_parser(ValueParser::os_string()),
)
.arg(
Expand Down Expand Up @@ -235,12 +234,12 @@ fn parse_command_line(config: Command, args: impl uucore::Args) -> UResult<Optio
}

fn print_current_context() -> Result<()> {
let op = "Getting security context of the current process";
let context = SecurityContext::current(false).map_err(|r| Error::from_selinux(op, r))?;
let context = SecurityContext::current(false)
.map_err(|r| Error::from_selinux("runcon-operation-getting-current-context", r))?;

let context = context
.to_c_string()
.map_err(|r| Error::from_selinux(op, r))?;
.map_err(|r| Error::from_selinux("runcon-operation-getting-current-context", r))?;

if let Some(context) = context {
let context = context.as_ref().to_str()?;
Expand All @@ -254,18 +253,22 @@ fn print_current_context() -> Result<()> {
fn set_next_exec_context(context: &OpaqueSecurityContext) -> Result<()> {
let c_context = context
.to_c_string()
.map_err(|r| Error::from_selinux("Creating new context", r))?;
.map_err(|r| Error::from_selinux("runcon-operation-creating-context", r))?;

let sc = SecurityContext::from_c_str(&c_context, false);

if sc.check() != Some(true) {
let ctx = OsStr::from_bytes(c_context.as_bytes());
let err = io::ErrorKind::InvalidInput.into();
return Err(Error::from_io1("Checking security context", ctx, err));
return Err(Error::from_io1(
"runcon-operation-checking-context",
ctx,
err,
));
}

sc.set_for_next_exec()
.map_err(|r| Error::from_selinux("Setting new security context", r))
.map_err(|r| Error::from_selinux("runcon-operation-setting-context", r))
}

fn get_plain_context(context: &OsStr) -> Result<OpaqueSecurityContext> {
Expand All @@ -276,36 +279,38 @@ fn get_plain_context(context: &OsStr) -> Result<OpaqueSecurityContext> {
let c_context = os_str_to_c_string(context)?;

OpaqueSecurityContext::from_c_str(&c_context)
.map_err(|r| Error::from_selinux("Creating new context", r))
.map_err(|r| Error::from_selinux("runcon-operation-creating-context", r))
}

fn get_transition_context(command: &OsStr) -> Result<SecurityContext> {
// Generate context based on process transition.
let sec_class = SecurityClass::from_name("process")
.map_err(|r| Error::from_selinux("Getting process security class", r))?;
.map_err(|r| Error::from_selinux("runcon-operation-getting-process-class", r))?;

// Get context of file to be executed.
let file_context = match SecurityContext::of_path(command, true, false) {
Ok(Some(context)) => context,

Ok(None) => {
let err = io::Error::from_raw_os_error(libc::ENODATA);
return Err(Error::from_io1("getfilecon", command, err));
return Err(Error::from_io1("runcon-operation-getfilecon", command, err));
}

Err(r) => {
let op = "Getting security context of command file";
return Err(Error::from_selinux(op, r));
return Err(Error::from_selinux(
"runcon-operation-getting-file-context",
r,
));
}
};

let process_context = SecurityContext::current(false)
.map_err(|r| Error::from_selinux("Getting security context of the current process", r))?;
.map_err(|r| Error::from_selinux("runcon-operation-getting-current-context", r))?;

// Compute result of process transition.
process_context
.of_labeling_decision(&file_context, sec_class, "")
.map_err(|r| Error::from_selinux("Computing result of process transition", r))
.map_err(|r| Error::from_selinux("runcon-operation-computing-transition", r))
}

fn get_initial_custom_opaque_context(
Expand All @@ -315,18 +320,17 @@ fn get_initial_custom_opaque_context(
let context = if compute_transition_context {
get_transition_context(command)?
} else {
SecurityContext::current(false).map_err(|r| {
Error::from_selinux("Getting security context of the current process", r)
})?
SecurityContext::current(false)
.map_err(|r| Error::from_selinux("runcon-operation-getting-current-context", r))?
};

let c_context = context
.to_c_string()
.map_err(|r| Error::from_selinux("Getting security context", r))?
.map_err(|r| Error::from_selinux("runcon-operation-getting-context", r))?
.unwrap_or_else(|| Cow::Owned(CString::default()));

OpaqueSecurityContext::from_c_str(c_context.as_ref())
.map_err(|r| Error::from_selinux("Creating new context", r))
.map_err(|r| Error::from_selinux("runcon-operation-creating-context", r))
}

fn get_custom_context(
Expand All @@ -347,16 +351,16 @@ fn get_custom_context(
let osc = get_initial_custom_opaque_context(compute_transition_context, command)?;

let list: &[(Option<&OsStr>, SetNewValueProc, &'static str)] = &[
(user, OSC::set_user, "Setting security context user"),
(role, OSC::set_role, "Setting security context role"),
(the_type, OSC::set_type, "Setting security context type"),
(range, OSC::set_range, "Setting security context range"),
(user, OSC::set_user, "runcon-operation-setting-user"),
(role, OSC::set_role, "runcon-operation-setting-role"),
(the_type, OSC::set_type, "runcon-operation-setting-type"),
(range, OSC::set_range, "runcon-operation-setting-range"),
];

for &(new_value, method, op) in list {
for &(new_value, method, op_key) in list {
if let Some(new_value) = new_value {
let c_new_value = os_str_to_c_string(new_value)?;
method(&osc, &c_new_value).map_err(|r| Error::from_selinux(op, r))?;
method(&osc, &c_new_value).map_err(|r| Error::from_selinux(op_key, r))?;
}
}
Ok(osc)
Expand Down Expand Up @@ -390,11 +394,15 @@ fn execute_command(command: &OsStr, arguments: &[OsString]) -> UResult<()> {
error_exit_status::COULD_NOT_EXECUTE
};

let err = Error::from_io1("Executing command", command, err);
let err = Error::from_io1("runcon-operation-executing-command", command, err);
Err(RunconError::with_code(exit_status, err).into())
}

fn os_str_to_c_string(s: &OsStr) -> Result<CString> {
CString::new(s.as_bytes())
.map_err(|_r| Error::from_io("CString::new()", io::ErrorKind::InvalidInput.into()))
CString::new(s.as_bytes()).map_err(|_r| {
Error::from_io(
"runcon-operation-cstring-new",
io::ErrorKind::InvalidInput.into(),
)
})
}
Loading