btrbk: generic input validation of command arguments

pull/30/head
Axel Burri 2015-02-28 13:49:36 +01:00
parent 056f6f9120
commit 372ec90685
1 changed files with 31 additions and 26 deletions

57
btrbk
View File

@ -87,6 +87,8 @@ my $loglevel = 1;
my $ip_addr_match = qr/(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/; my $ip_addr_match = qr/(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/;
my $host_name_match = qr/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])/; my $host_name_match = qr/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])/;
my $file_match = qr/[0-9a-zA-Z_\-\.\/]+/; my $file_match = qr/[0-9a-zA-Z_\-\.\/]+/;
my $ssh_prefix_match = qr/ssh:\/\/($ip_addr_match|$host_name_match)/;
$SIG{__DIE__} = sub { $SIG{__DIE__} = sub {
print STDERR "\nERROR: process died unexpectedly (btrbk v$VERSION)"; print STDERR "\nERROR: process died unexpectedly (btrbk v$VERSION)";
@ -213,7 +215,7 @@ sub check_file($$$$)
my $config_file = shift; # only for error text my $config_file = shift; # only for error text
if($accept->{ssh} && ($file =~ /^ssh:\/\//)) { if($accept->{ssh} && ($file =~ /^ssh:\/\//)) {
unless($file =~ /^ssh:\/\/($ip_addr_match|$host_name_match)\/$file_match$/) { unless($file =~ /^$ssh_prefix_match\/$file_match$/) {
ERROR "Ambiguous ssh url for option \"$key\" in \"$config_file\" line $.: $file"; ERROR "Ambiguous ssh url for option \"$key\" in \"$config_file\" line $.: $file";
return undef; return undef;
} }
@ -971,6 +973,8 @@ MAIN:
} }
my ($action_run, $action_info, $action_tree, $action_diff, $action_origin); my ($action_run, $action_info, $action_tree, $action_diff, $action_origin);
my @subvol_args;
my $args_expected = 0;
if(($command eq "run") || ($command eq "dryrun")) { if(($command eq "run") || ($command eq "dryrun")) {
$action_run = 1; $action_run = 1;
$dryrun = 1 if($command eq "dryrun"); $dryrun = 1 if($command eq "dryrun");
@ -983,15 +987,36 @@ MAIN:
} }
elsif ($command eq "diff") { elsif ($command eq "diff") {
$action_diff = 1; $action_diff = 1;
$args_expected = 2;
@subvol_args = @ARGV;
} }
elsif ($command eq "origin") { elsif ($command eq "origin") {
$action_origin = 1; $action_origin = 1;
$args_expected = 1;
@subvol_args = @ARGV;
} }
else { else {
ERROR "Unrecognized command: $command"; ERROR "Unrecognized command: $command";
HELP_MESSAGE(0); HELP_MESSAGE(0);
exit 1; exit 1;
} }
if($args_expected != scalar(@ARGV)) {
ERROR "Incorrect number of arguments";
HELP_MESSAGE(0);
exit 1;
}
# input validation
foreach (@subvol_args) {
s/\/+$//; # remove trailing slash
unless(/^(($ssh_prefix_match)?\/$file_match)$/) { # matches ssh statement or absolute file
ERROR "Bad argument: not a subvolume declaration: $_";
HELP_MESSAGE(0);
exit 1;
}
$_ = $1; # untaint argument
}
INFO "$version_info (" . localtime($start_time) . ")"; INFO "$version_info (" . localtime($start_time) . ")";
@ -1000,24 +1025,9 @@ MAIN:
# #
# print snapshot diff # print snapshot diff
# #
my $src_vol = shift @ARGV; my $src_vol = $subvol_args[0] || die;
my $target_vol = shift @ARGV; my $target_vol = $subvol_args[1] || die;
unless($src_vol && $target_vol) { # FIXME: allow ssh:// src/dest (does not work since the configuration is not yet read).
ERROR "Missing subvolume argument for \"diff\" command";
HELP_MESSAGE(0);
exit 1;
}
# untaint arguments
unless($src_vol =~ /^($file_match)$/) {
ERROR "bad argument: not a file: $src_vol";
exit 1;
}
$src_vol = $1;
unless($target_vol =~ /^($file_match)$/) {
ERROR "bad argument: not a file: $target_vol";
exit 1;
}
$target_vol = $1;
my $src_detail = btr_subvolume_detail($src_vol); my $src_detail = btr_subvolume_detail($src_vol);
unless($src_detail) { exit 1; } unless($src_detail) { exit 1; }
@ -1207,14 +1217,9 @@ MAIN:
# #
# print origin information # print origin information
# #
my $subvol = shift @ARGV; my $subvol = $subvol_args[0] || die;
my $dump_uuid = 0; my $dump_uuid = 0;
unless($subvol) {
ERROR "Missing subvolume argument for \"origin\" command";
HELP_MESSAGE(0);
exit 1;
}
$subvol =~ s/\/+$//; # remove trailing slash
my $uuid; my $uuid;
foreach(values %uuid_info) { foreach(values %uuid_info) {
if($_->{FS_PATH} eq $subvol) { if($_->{FS_PATH} eq $subvol) {