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.master
parent
bfff0e4feb
commit
bd404e6937
|
@ -870,11 +870,9 @@ impl ImapType {
|
||||||
let server_password = if !s.extra.contains_key("server_password_command") {
|
let server_password = if !s.extra.contains_key("server_password_command") {
|
||||||
get_conf_val!(s["server_password"])?.to_string()
|
get_conf_val!(s["server_password"])?.to_string()
|
||||||
} else {
|
} else {
|
||||||
let invocation = get_conf_val!(s["server_password_command"])?
|
let invocation = get_conf_val!(s["server_password_command"])?;
|
||||||
.split_whitespace()
|
let output = std::process::Command::new("sh")
|
||||||
.collect::<Vec<&str>>();
|
.args(&["-c", invocation])
|
||||||
let output = std::process::Command::new(invocation[0])
|
|
||||||
.args(&invocation[1..])
|
|
||||||
.stdin(std::process::Stdio::piped())
|
.stdin(std::process::Stdio::piped())
|
||||||
.stdout(std::process::Stdio::piped())
|
.stdout(std::process::Stdio::piped())
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(std::process::Stdio::piped())
|
||||||
|
|
|
@ -913,11 +913,13 @@ impl Component for Composer {
|
||||||
context.input_kill();
|
context.input_kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
let parts = split_command!(editor);
|
let editor_cmd = format!("{} {}", editor, f.path().display());
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
log(
|
||||||
match Command::new(cmd)
|
format!("Executing: sh -c \"{}\"", editor_cmd.replace("\"", "\\\"")),
|
||||||
.args(args)
|
DEBUG,
|
||||||
.arg(&f.path())
|
);
|
||||||
|
match Command::new("sh")
|
||||||
|
.args(&["-c", &editor_cmd])
|
||||||
.stdin(Stdio::inherit())
|
.stdin(Stdio::inherit())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
@ -963,8 +965,7 @@ impl Component for Composer {
|
||||||
UIEvent::Action(ref a) => {
|
UIEvent::Action(ref a) => {
|
||||||
match a {
|
match a {
|
||||||
Action::Compose(ComposeAction::AddAttachmentPipe(ref cmd)) => {
|
Action::Compose(ComposeAction::AddAttachmentPipe(ref cmd)) => {
|
||||||
let parts = split_command!(cmd);
|
if cmd.is_empty() {
|
||||||
if parts.is_empty() {
|
|
||||||
context.replies.push_back(UIEvent::Notification(
|
context.replies.push_back(UIEvent::Notification(
|
||||||
None,
|
None,
|
||||||
format!("pipe cmd value is invalid: {}", cmd),
|
format!("pipe cmd value is invalid: {}", cmd),
|
||||||
|
@ -972,10 +973,9 @@ impl Component for Composer {
|
||||||
));
|
));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
|
||||||
let f = create_temp_file(&[], None, None, true);
|
let f = create_temp_file(&[], None, None, true);
|
||||||
match std::process::Command::new(cmd)
|
match std::process::Command::new("sh")
|
||||||
.args(args)
|
.args(&["-c", cmd])
|
||||||
.stdin(std::process::Stdio::null())
|
.stdin(std::process::Stdio::null())
|
||||||
.stdout(std::process::Stdio::from(f.file()))
|
.stdout(std::process::Stdio::from(f.file()))
|
||||||
.spawn()
|
.spawn()
|
||||||
|
@ -1183,10 +1183,8 @@ pub fn send_draft(
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
let format_flowed = *mailbox_acc_settings!(context[account_cursor].composing.format_flowed);
|
let format_flowed = *mailbox_acc_settings!(context[account_cursor].composing.format_flowed);
|
||||||
let parts = split_command!(mailbox_acc_settings!(
|
let cmd = mailbox_acc_settings!(context[account_cursor].composing.mailer_cmd);
|
||||||
context[account_cursor].composing.mailer_cmd
|
if cmd.is_empty() {
|
||||||
));
|
|
||||||
if parts.is_empty() {
|
|
||||||
context.replies.push_back(UIEvent::Notification(
|
context.replies.push_back(UIEvent::Notification(
|
||||||
None,
|
None,
|
||||||
String::from("mailer_cmd configuration value is empty"),
|
String::from("mailer_cmd configuration value is empty"),
|
||||||
|
@ -1195,9 +1193,8 @@ pub fn send_draft(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let bytes;
|
let bytes;
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
let mut msmtp = Command::new("sh")
|
||||||
let mut msmtp = Command::new(cmd)
|
.args(&["-c", cmd])
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
|
|
@ -170,10 +170,8 @@ impl MailView {
|
||||||
)
|
)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
{
|
{
|
||||||
let parts = split_command!(filter_invocation);
|
let command_obj = Command::new("sh")
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
.args(&["-c", filter_invocation])
|
||||||
let command_obj = Command::new(cmd)
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
|
@ -98,10 +98,8 @@ impl EnvelopeView {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let settings = &context.settings;
|
let settings = &context.settings;
|
||||||
if let Some(filter_invocation) = settings.pager.html_filter.as_ref() {
|
if let Some(filter_invocation) = settings.pager.html_filter.as_ref() {
|
||||||
let parts = split_command!(filter_invocation);
|
let command_obj = Command::new("sh")
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
.args(&["-c", filter_invocation])
|
||||||
let command_obj = Command::new(cmd)
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
|
@ -38,10 +38,8 @@ impl HtmlView {
|
||||||
let settings = &context.settings;
|
let settings = &context.settings;
|
||||||
let mut display_text = if let Some(filter_invocation) = settings.pager.html_filter.as_ref()
|
let mut display_text = if let Some(filter_invocation) = settings.pager.html_filter.as_ref()
|
||||||
{
|
{
|
||||||
let parts = split_command!(filter_invocation);
|
let command_obj = Command::new("sh")
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
.args(&["-c", filter_invocation])
|
||||||
let command_obj = Command::new(cmd)
|
|
||||||
.args(args)
|
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
|
@ -676,10 +676,8 @@ impl Account {
|
||||||
}
|
}
|
||||||
pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> {
|
pub fn refresh(&mut self, mailbox_hash: MailboxHash) -> Result<()> {
|
||||||
if let Some(ref refresh_command) = self.settings.conf().refresh_command {
|
if let Some(ref refresh_command) = self.settings.conf().refresh_command {
|
||||||
let parts = crate::split_command!(refresh_command);
|
let child = std::process::Command::new("sh")
|
||||||
let (cmd, args) = (parts[0], &parts[1..]);
|
.args(&["-c", refresh_command])
|
||||||
let child = std::process::Command::new(cmd)
|
|
||||||
.args(args)
|
|
||||||
.stdin(std::process::Stdio::null())
|
.stdin(std::process::Stdio::null())
|
||||||
.stdout(std::process::Stdio::null())
|
.stdout(std::process::Stdio::null())
|
||||||
.stderr(std::process::Stdio::piped())
|
.stderr(std::process::Stdio::piped())
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
/*! Find mailcap entries to execute attachments.
|
/*! Find mailcap entries to execute attachments.
|
||||||
*/
|
*/
|
||||||
use crate::split_command;
|
|
||||||
use crate::state::Context;
|
use crate::state::Context;
|
||||||
use crate::types::{create_temp_file, ForkType, UIEvent};
|
use crate::types::{create_temp_file, ForkType, UIEvent};
|
||||||
use melib::attachments::decode;
|
use melib::attachments::decode;
|
||||||
|
@ -180,10 +179,15 @@ impl MailcapEntry {
|
||||||
{
|
{
|
||||||
context.input_kill();
|
context.input_kill();
|
||||||
}
|
}
|
||||||
|
let cmd_string = format!("{} {}", cmd, args.join(" "));
|
||||||
|
melib::log(
|
||||||
|
format!("Executing: sh -c \"{}\"", cmd_string.replace("\"", "\\\"")),
|
||||||
|
melib::DEBUG,
|
||||||
|
);
|
||||||
if copiousoutput {
|
if copiousoutput {
|
||||||
let out = if needs_stdin {
|
let out = if needs_stdin {
|
||||||
let mut child = Command::new(cmd)
|
let mut child = Command::new("sh")
|
||||||
.args(args)
|
.args(&["-c", &cmd_string])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
@ -191,8 +195,8 @@ impl MailcapEntry {
|
||||||
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
||||||
child.wait_with_output()?.stdout
|
child.wait_with_output()?.stdout
|
||||||
} else {
|
} else {
|
||||||
let child = Command::new(cmd)
|
let child = Command::new("sh")
|
||||||
.args(args)
|
.args(&["-c", &cmd_string])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
@ -213,8 +217,8 @@ impl MailcapEntry {
|
||||||
debug!(pager.wait_with_output()?.stdout);
|
debug!(pager.wait_with_output()?.stdout);
|
||||||
} else {
|
} else {
|
||||||
if needs_stdin {
|
if needs_stdin {
|
||||||
let mut child = Command::new(cmd)
|
let mut child = Command::new("sh")
|
||||||
.args(args)
|
.args(&["-c", &cmd_string])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
@ -222,8 +226,8 @@ impl MailcapEntry {
|
||||||
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
child.stdin.as_mut().unwrap().write_all(&decode(a, None))?;
|
||||||
debug!(child.wait_with_output()?.stdout);
|
debug!(child.wait_with_output()?.stdout);
|
||||||
} else {
|
} else {
|
||||||
let child = Command::new(cmd)
|
let child = Command::new("sh")
|
||||||
.args(args)
|
.args(&["-c", &cmd_string])
|
||||||
.stdin(Stdio::inherit())
|
.stdin(Stdio::inherit())
|
||||||
.stdout(Stdio::inherit())
|
.stdout(Stdio::inherit())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
|
@ -176,9 +176,9 @@ impl PluginManager {
|
||||||
match plugin.kind {
|
match plugin.kind {
|
||||||
PluginKind::LongLived => {
|
PluginKind::LongLived => {
|
||||||
/* spawn thread */
|
/* spawn thread */
|
||||||
let parts = split_command!(&plugin.executable);
|
let inv = &plugin.executable;
|
||||||
let child = std::process::Command::new(&parts[0])
|
let child = std::process::Command::new("sh")
|
||||||
.args(&parts[1..])
|
.args(&["-c", inv])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
@ -241,9 +241,9 @@ impl PluginManager {
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
PluginKind::Filter => {
|
PluginKind::Filter => {
|
||||||
let parts = split_command!(&plugin.executable);
|
let inv = &plugin.executable;
|
||||||
let mut child = std::process::Command::new(&parts[0])
|
let mut child = std::process::Command::new("sh")
|
||||||
.args(&parts[1..])
|
.args(&["-c", inv])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
|
@ -238,9 +238,9 @@ impl PluginBackend {
|
||||||
&plugin.name, &plugin.kind
|
&plugin.name, &plugin.kind
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
let parts = split_command!(&plugin.executable);
|
let inv = &plugin.executable;
|
||||||
let child = std::process::Command::new(&parts[0])
|
let child = std::process::Command::new("sh")
|
||||||
.args(&parts[1..])
|
.args(&["-c", inv])
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
|
@ -115,19 +115,12 @@ pub fn create_pty(
|
||||||
std::process::exit(-1);
|
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(
|
if let Err(e) = nix::unistd::execv(
|
||||||
&CString::new(cmd).unwrap(),
|
&CString::new("sh").unwrap(),
|
||||||
_parts
|
&[
|
||||||
.iter()
|
&CString::new("-c").unwrap(),
|
||||||
.map(|a| a.as_c_str())
|
&CString::new(command.as_bytes()).unwrap(),
|
||||||
.collect::<Vec<&_>>()
|
],
|
||||||
.as_slice(),
|
|
||||||
) {
|
) {
|
||||||
log(format!("Could not execute `{}`: {}", command, e,), ERROR);
|
log(format!("Could not execute `{}`: {}", command, e,), ERROR);
|
||||||
std::process::exit(-1);
|
std::process::exit(-1);
|
||||||
|
|
Loading…
Reference in New Issue