Imported Upstream version 3.2.0
[debian/amanda] / server-src / amidxtaped.pl
index 43648dcc0d13f44d1c6bd44020eb8149ffc07cff..ea22fc28e9f88e564f22fca30f1c73be6f4bc69d 100644 (file)
@@ -108,44 +108,6 @@ sub user_request {
     };
 };
 
-##
-# Clerk Feedback class
-
-package main::Feedback;
-use Amanda::Recovery::Clerk;
-use Amanda::Util qw( weaken_ref );
-use base 'Amanda::Recovery::Clerk::Feedback';
-
-sub new {
-    my $class = shift;
-    my %params = @_;
-
-    my $self = bless {
-       clientservice => $params{'clientservice'}
-    }, $class;
-
-    # (weak ref here to eliminate reference loop)
-    weaken_ref($self->{'clientservice'});
-
-    return $self;
-}
-
-sub part_notif {
-    my $self = shift;
-
-    my ($label, $filenum, $hdr) = @_;
-    $self->{'clientservice'}->sendmessage("restoring part $hdr->{'partnum'} " .
-         "from '$label' file $filenum");
-}
-
-sub holding_notif {
-    my $self = shift;
-
-    my ($holding_file, $hdr) = @_;
-    $self->{'clientservice'}->sendmessage("restoring from holding " .
-               "file $holding_file");
-}
-
 ##
 # ClientService class
 
@@ -164,6 +126,8 @@ use Amanda::Recovery::Clerk;
 use Amanda::Recovery::Planner;
 use Amanda::Recovery::Scan;
 use Amanda::DB::Catalog;
+use Amanda::Disklist;
+use Amanda::Logfile qw( match_disk match_host );
 
 # Note that this class performs its control IO synchronously.  This is adequate
 # for this service, as it never receives unsolicited input from the remote
@@ -266,13 +230,22 @@ sub read_command {
        $self->{'their_features'} = Amanda::Feature::Set->from_string($command->{'FEATURES'});
     }
 
-    if ($command->{'CONFIG'}) {
-       config_init($CONFIG_INIT_EXPLICIT_NAME, $command->{'CONFIG'});
-       my ($cfgerr_level, @cfgerr_errors) = config_errors();
-       if ($cfgerr_level >= $CFGERR_ERRORS) {
-           die "configuration errors; aborting connection";
-       }
-       Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER_PREFERRED);
+    # load the configuration
+    if (!$command->{'CONFIG'}) {
+       die "no CONFIG line given";
+    }
+    config_init($CONFIG_INIT_EXPLICIT_NAME, $command->{'CONFIG'});
+    my ($cfgerr_level, @cfgerr_errors) = config_errors();
+    if ($cfgerr_level >= $CFGERR_ERRORS) {
+       die "configuration errors; aborting connection";
+    }
+    Amanda::Util::finish_setup($RUNNING_AS_DUMPUSER_PREFERRED);
+
+    # and the disklist
+    my $diskfile = Amanda::Config::config_dir_relative(getconf($CNF_DISKFILE));
+    $cfgerr_level = Amanda::Disklist::read_disklist('filename' => $diskfile);
+    if ($cfgerr_level >= $CFGERR_ERRORS) {
+       die "Errors processing disklist";
     }
 
     $self->setup_data_stream();
@@ -334,7 +307,8 @@ sub make_plan {
            $self->{'command'}{'HOST'},
            $disk,
            $self->{'command'}{'DATESTAMP'},
-           undef); # amidxtaped protocol does not provide a level (!?)
+           undef,  # amidxtaped protocol does not provide a level (!?)
+           undef); # amidxtaped protocol does not provide a write timestamp
     }
 
     # figure out if this is a holding-disk recovery
@@ -382,7 +356,8 @@ sub make_plan {
     $scan->{'scan_conf'}->{'notfound'} = Amanda::Recovery::Scan::SCAN_ASK;
 
     $self->{'clerk'} = Amanda::Recovery::Clerk->new(
-       feedback => main::Feedback->new($chg, undef),
+       # note that we don't have any use for clerk_notif's, so we don't pass
+       # a feedback object
        scan => $scan);
 
     if ($is_holding) {
@@ -438,6 +413,51 @@ sub plan_cb {
        return $self->quit();
     }
 
+    # check that the request-limit for this DLE allows this recovery.  because
+    # of the bass-ackward way that amrecover specifies the dump to us, we can't
+    # check the results until *after* the plan was created.
+    my $dump = $plan->{'dumps'}->[0];
+    my $dle = Amanda::Disklist::get_disk($dump->{'hostname'}, $dump->{'diskname'});
+    my $recovery_limit;
+    if ($dle && dumptype_seen($dle->{'config'}, $DUMPTYPE_RECOVERY_LIMIT)) {
+       debug("using DLE recovery limit");
+       $recovery_limit = dumptype_getconf($dle->{'config'}, $DUMPTYPE_RECOVERY_LIMIT);
+    } elsif (getconf_seen($CNF_RECOVERY_LIMIT)) {
+       debug("using global recovery limit as default");
+       $recovery_limit = getconf($CNF_RECOVERY_LIMIT);
+    }
+    my $peer = $ENV{'AMANDA_AUTHENTICATED_PEER'};
+    if (defined $recovery_limit) { # undef -> no recovery limit
+       if (!$peer) {
+           warning("a recovery limit is specified for this DLE, but no authenticted ".
+                   "peer name is available; rejecting request.");
+           $self->sendmessage("No matching dumps found");
+           return $self->quit();
+       }
+       my $matched = 0;
+       for my $rl (@$recovery_limit) {
+           if (!defined $rl) {
+               # handle same-host with a case-insensitive string compare, not match_host
+               if (lc($peer) eq lc($dump->{'hostname'})) {
+                   $matched = 1;
+                   last;
+               }
+           }
+
+           # otherwise use match_host to allow match expressions
+           if (match_host($rl, $peer)) {
+               $matched = 1;
+               last;
+           }
+       }
+       if (!$matched) {
+           warning("authenticated peer '$peer' did not match recovery-limit ".
+                   "config; rejecting request");
+           $self->sendmessage("No matching dumps found");
+           return $self->quit();
+       }
+    }
+
     if (!$self->{'their_features'}->has($Amanda::Feature::fe_recover_splits)) {
        # if we have greater than one volume, we may need to prompt for a new
        # volume in mid-recovery.  Sadly, we have no way to inform the client of
@@ -476,11 +496,11 @@ sub xfer_src_cb {
        if ($header->{'srv_encrypt'}) {
            push @filters,
                Amanda::Xfer::Filter::Process->new(
-                   [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0);
+                   [ $header->{'srv_encrypt'}, $header->{'srv_decrypt_opt'} ], 0, 1);
        } elsif ($header->{'clnt_encrypt'}) {
            push @filters,
                Amanda::Xfer::Filter::Process->new(
-                   [ $header->{'clnt_encrypt'}, $header->{'clnt_decrypt_opt'} ], 0);
+                   [ $header->{'clnt_encrypt'}, $header->{'clnt_decrypt_opt'} ], 0, 1);
        } else {
            $self->sendmessage("could not decrypt encrypted dump: no program specified");
            return $self->quit();
@@ -502,17 +522,17 @@ sub xfer_src_cb {
            # TODO: this assumes that srvcompprog takes "-d" to decrypt
            push @filters,
                Amanda::Xfer::Filter::Process->new(
-                   [ $header->{'srvcompprog'}, "-d" ], 0);
+                   [ $header->{'srvcompprog'}, "-d" ], 0, 1);
        } elsif ($header->{'clntcompprog'}) {
            # TODO: this assumes that clntcompprog takes "-d" to decrypt
            push @filters,
                Amanda::Xfer::Filter::Process->new(
-                   [ $header->{'clntcompprog'}, "-d" ], 0);
+                   [ $header->{'clntcompprog'}, "-d" ], 0, 1);
        } else {
            push @filters,
                Amanda::Xfer::Filter::Process->new(
                    [ $Amanda::Constants::UNCOMPRESS_PATH,
-                     $Amanda::Constants::UNCOMPRESS_OPT ], 0);
+                     $Amanda::Constants::UNCOMPRESS_OPT ], 0, 1);
        }
 
        # adjust the header