Execute user shell commands with /bin/sh

Execute user provided command invocations $CMD such as `editor_cmd` with
`/bin/sh` as `/bin/sh -c "$CMD"

Previously, user commands were split by whitespace which must trigger
erroneous behavior if quotes are involved.
This commit is contained in:
Manos Pitsidianakis 2020-05-28 16:27:02 +03:00
parent bfff0e4feb
commit bd404e6937
No known key found for this signature in database
GPG Key ID: 73627C2F690DF710
10 changed files with 52 additions and 68 deletions

View File

@ -870,11 +870,9 @@ impl ImapType {
let server_password = if !s.extra.contains_key("server_password_command") {
get_conf_val!(s["server_password"])?.to_string()
} else {
let invocation = get_conf_val!(s["server_password_command"])?
.split_whitespace()
.collect::<Vec<&str>>();
let output = std::process::Command::new(invocation[0])
.args(&invocation[1..])
let invocation = get_conf_val!(s["server_password_command"])?;
let output = std::process::Command::new("sh")
.args(&["-c", invocation])
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())

View File

@ -913,11 +913,13 @@ impl Component for Composer {
context.input_kill();
}
let parts = split_command!(editor);
let (cmd, args) = (parts[0], &parts[1..]);
match Command::new(cmd)
.args(args)
.arg(&f.path())
let editor_cmd = format!("{} {}", editor, f.path().display());
log(
format!("Executing: sh -c \"{}\"", editor_cmd.replace("\"", "\\\"")),
DEBUG,
);
match Command::new("sh")
.args(&["-c", &editor_cmd])
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.spawn()
@ -963,8 +965,7 @@ impl Component for Composer {
UIEvent::Action(ref a) => {
match a {
Action::Compose(ComposeAction::AddAttachmentPipe(ref cmd)) => {
let parts = split_command!(cmd);
if parts.is_empty() {
if cmd.is_empty() {
context.replies.push_back(UIEvent::Notification(
None,
format!("pipe cmd value is invalid: {}", cmd),
@ -972,10 +973,9 @@ impl Component for Composer {
));
return false;
}
let (cmd, args) = (parts[0], &parts[1..]);
let f = create_temp_file(&[], None, None, true);
match std::process::Command::new(cmd)
.args(args)
match std::process::Command::new("sh")
.args(&["-c", cmd])
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::from(f.file()))
.spawn()
@ -1183,10 +1183,8 @@ pub fn send_draft(
use std::io::Write;
use std::process::{Command, Stdio};
let format_flowed = *mailbox_acc_settings!(context[account_cursor].composing.format_flowed);
let parts = split_command!(mailbox_acc_settings!(
context[account_cursor].composing.mailer_cmd
));
if parts.is_empty() {
let cmd = mailbox_acc_settings!(context[account_cursor].composing.mailer_cmd);
if cmd.is_empty() {
context.replies.push_back(UIEvent::Notification(
None,
String::from("mailer_cmd configuration value is empty"),
@ -1195,9 +1193,8 @@ pub fn send_draft(
return false;
}
let bytes;
let (cmd, args) = (parts[0], &parts[1..]);
let mut msmtp = Command::new(cmd)
.args(args)
let mut msmtp = Command::new("sh")
.args(&["-c", cmd])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()

View File

@ -170,10 +170,8 @@ impl MailView {
)
.as_ref()
{
let parts = split_command!(filter_invocation);
let (cmd, args) = (parts[0], &parts[1..]);
let command_obj = Command::new(cmd)
.args(args)
let command_obj = Command::new("sh")
.args(&["-c", filter_invocation])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn();

View File

@ -98,10 +98,8 @@ impl EnvelopeView {
use std::io::Write;
let settings = &context.settings;
if let Some(filter_invocation) = settings.pager.html_filter.as_ref() {
let parts = split_command!(filter_invocation);
let (cmd, args) = (parts[0], &parts[1..]);
let command_obj = Command::new(cmd)
.args(args)
let command_obj = Command::new("sh")
.args(&["-c", filter_invocation])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn();

View File

@ -38,10 +38,8 @@ impl HtmlView {
let settings = &context.settings;
let mut display_text = if let Some(filter_invocation) = settings.pager.html_filter.as_ref()
{
let parts = split_command!(filter_invocation);
let (cmd, args) = (parts[0], &parts[1..]);
let command_obj = Command::new(cmd)
.args(args)
let command_obj = Command::new("sh")
.args(&["-c", filter_invocation])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn();

View File

@ -676,10 +676,8 @@ impl Account {
}
pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> {
if let Some(ref refresh_command) = self.settings.conf().refresh_command {
let parts = crate::split_command!(refresh_command);
let (cmd, args) = (parts[0], &parts[1..]);
let child = std::process::Command::new(cmd)
.args(args)
let child = std::process::Command::new("sh")
.args(&["-c", refresh_command])
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::piped())

View File

@ -21,7 +21,6 @@
/*! Find mailcap entries to execute attachments.
*/
use crate::split_command;
use crate::state::Context;
use crate::types::{create_temp_file, ForkType, UIEvent};
use melib::attachments::decode;
@ -180,10 +179,15 @@ impl MailcapEntry {
{
context.input_kill();
}
let cmd_string = format!("{} {}", cmd, args.join(" "));
melib::log(
format!("Executing: sh -c \"{}\"", cmd_string.replace("\"", "\\\"")),
melib::DEBUG,
);
if copiousoutput {
let out = if needs_stdin {
let mut child = Command::new(cmd)
.args(args)
let mut child = Command::new("sh")
.args(&["-c", &cmd_string])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
@ -191,8 +195,8 @@ impl MailcapEntry {
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
child.wait_with_output()?.stdout
} else {
let child = Command::new(cmd)
.args(args)
let child = Command::new("sh")
.args(&["-c", &cmd_string])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
@ -213,8 +217,8 @@ impl MailcapEntry {
debug!(pager.wait_with_output()?.stdout);
} else {
if needs_stdin {
let mut child = Command::new(cmd)
.args(args)
let mut child = Command::new("sh")
.args(&["-c", &cmd_string])
.stdin(Stdio::piped())
.stdout(Stdio::inherit())
.spawn()?;
@ -222,8 +226,8 @@ impl MailcapEntry {
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
debug!(child.wait_with_output()?.stdout);
} else {
let child = Command::new(cmd)
.args(args)
let child = Command::new("sh")
.args(&["-c", &cmd_string])
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())
.spawn()?;

View File

@ -176,9 +176,9 @@ impl PluginManager {
match plugin.kind {
PluginKind::LongLived => {
/* spawn thread */
let parts = split_command!(&plugin.executable);
let child = std::process::Command::new(&parts[0])
.args(&parts[1..])
let inv = &plugin.executable;
let child = std::process::Command::new("sh")
.args(&["-c", inv])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
@ -241,9 +241,9 @@ impl PluginManager {
return reply;
}
PluginKind::Filter => {
let parts = split_command!(&plugin.executable);
let mut child = std::process::Command::new(&parts[0])
.args(&parts[1..])
let inv = &plugin.executable;
let mut child = std::process::Command::new("sh")
.args(&["-c", inv])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;

View File

@ -238,9 +238,9 @@ impl PluginBackend {
&plugin.name, &plugin.kind
)));
}
let parts = split_command!(&plugin.executable);
let child = std::process::Command::new(&parts[0])
.args(&parts[1..])
let inv = &plugin.executable;
let child = std::process::Command::new("sh")
.args(&["-c", inv])
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;

View File

@ -115,19 +115,12 @@ pub fn create_pty(
std::process::exit(-1);
}
}
let parts = split_command!(command);
let (cmd, _) = (parts[0], &parts[1..]);
let _parts = parts
.iter()
.map(|&a| CString::new(a).unwrap())
.collect::<Vec<CString>>();
if let Err(e) = nix::unistd::execv(
&CString::new(cmd).unwrap(),
_parts
.iter()
.map(|a| a.as_c_str())
.collect::<Vec<&_>>()
.as_slice(),
&CString::new("sh").unwrap(),
&[
&CString::new("-c").unwrap(),
&CString::new(command.as_bytes()).unwrap(),
],
) {
log(format!("Could not execute `{}`: {}", command, e,), ERROR);
std::process::exit(-1);