mirror of https://github.com/digint/btrbk
btrbk: quote unsafe characters in shell commands
As filenames can contain meta characters like '$', we can't just put ssh commands in double quotes. E.g. the following would trigger variable expansion on local shell: ssh example.com "ls -l 'evil$x'" Instead, we quote the ssh using single quotes (adding the need to escape single quotes), while also quoting unsafe filenames using single quotes. The above becomes: ssh example.com 'ls -l '\''evil$x'\''' Or more complex, for a file named "file with'single quotes'": ssh example.com 'ls -l '\''file with'\''\'\'''\''single quotes'\''\'\'''\'''\''' On the remote shell, this will expand to: ls -l 'file with'\''single quotes'\'''unsafe-filenames
parent
d7f6d5fecf
commit
acc7f9fc83
13
btrbk
13
btrbk
|
@ -773,18 +773,24 @@ sub _piped_cmd_txt($)
|
||||||
return $cmd;
|
return $cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub quoteshell(@) {
|
||||||
|
# replace ' -> '\''
|
||||||
|
join ' ', map { "'" . s/'/'\\''/gr . "'" } @_
|
||||||
|
}
|
||||||
|
|
||||||
sub _safe_cmd($$)
|
sub _safe_cmd($$)
|
||||||
{
|
{
|
||||||
# NOTE: this function alters $aref: hashes of form: "{ unsafe => 'string' }" get translated to "string"
|
# NOTE: this function alters $aref: hashes of form: "{ unsafe => 'string' }" get translated to "'string'"
|
||||||
my $aref = shift;
|
my $aref = shift;
|
||||||
my $offending = shift;
|
my $offending = shift;
|
||||||
foreach(@$aref) {
|
foreach(@$aref) {
|
||||||
if(ref($_) eq 'HASH') {
|
if(ref($_) eq 'HASH') {
|
||||||
$_ = $_->{unsafe}; # replace in-place
|
$_ = $_->{unsafe}; # replace in-place
|
||||||
# NOTE: all files must be absolute
|
# NOTE: all files must be absolute (if not, check for leading dash '-' here!)
|
||||||
unless(defined(check_file($_, { absolute => 1 }))) {
|
unless(defined(check_file($_, { absolute => 1 }))) {
|
||||||
push @$offending, "\"$_\"";
|
push @$offending, "\"$_\"";
|
||||||
}
|
}
|
||||||
|
$_ = quoteshell($_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return join(' ', @$aref);
|
return join(' ', @$aref);
|
||||||
|
@ -900,7 +906,8 @@ sub run_cmd(@)
|
||||||
|
|
||||||
my $rsh_text = _safe_cmd($href->{rsh}, \@unsafe_cmd);
|
my $rsh_text = _safe_cmd($href->{rsh}, \@unsafe_cmd);
|
||||||
return undef unless(defined($rsh_text));
|
return undef unless(defined($rsh_text));
|
||||||
$href->{cmd_text} = $rsh_text . " '" . _piped_cmd_txt(\@rsh_cmd_pipe) . "'";
|
|
||||||
|
$href->{cmd_text} = $rsh_text . ' ' . quoteshell(_piped_cmd_txt(\@rsh_cmd_pipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
# local stream_buffer, rate_limit and show_progress in front of stream sink
|
# local stream_buffer, rate_limit and show_progress in front of stream sink
|
||||||
|
|
Loading…
Reference in New Issue