From 770e87a0576bd99df3651e0538194f181a9a20ce Mon Sep 17 00:00:00 2001 From: erickson Date: Tue, 22 Dec 2009 19:48:40 +0000 Subject: [PATCH] patch from Joe Atzberger to provide support for using SSh keys, including new key file params and some logic to find keyfiles in the default location git-svn-id: svn://svn.open-ils.org/ILS/trunk@15226 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- .../Application/Trigger/Reactor/SendFile.pm | 160 ++++++++++++++++-- 1 file changed, 146 insertions(+), 14 deletions(-) diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor/SendFile.pm b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor/SendFile.pm index 6a89da6cf9..70f343abfe 100644 --- a/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor/SendFile.pm +++ b/Open-ILS/src/perlmods/OpenILS/Application/Trigger/Reactor/SendFile.pm @@ -7,6 +7,7 @@ use OpenSRF::Utils::Logger qw/:logger/; use Data::Dumper; use Net::uFTP; +use Net::SSH2; # because uFTP doesn't handle SSH keys (yet?) use File::Temp; $Data::Dumper::Indent = 0; @@ -14,6 +15,8 @@ $Data::Dumper::Indent = 0; use strict; use warnings; +our %keyfiles = (); + sub ABOUT { return < SSH_PUBLICKEY + my $force = (@_ ? shift : 0); + return %keyfiles if (%keyfiles and not $force); # caching + $logger->info("Checking for SSH keyfiles" . ($force ? ' (ignoring cache)' : '')); + %keyfiles = (); # reset to empty + my @dirs = plausible_dirs(); + $logger->debug(scalar(@dirs) . " plausible dirs: " . join(', ', @dirs)); + foreach my $dir (@dirs) { + foreach my $key (qw/rsa dsa/) { + my $private = "$dir/id_$key"; + my $public = "$dir/id_$key.pub"; + unless (-r $private) { + $logger->debug("Key '$private' cannot be read: $!"); + next; + } + unless (-r $public) { + $logger->debug("Key '$public' cannot be read: $!"); + next; + } + $keyfiles{$private} = $public; + } + } + return %keyfiles; +} + +sub param_keys { + my $params = shift; + my %keys = (); + if ($params->{ssh_publickey } and not $params->{ssh_privatekey}) { + $params->{ssh_privatekey} = $params->{ssh_publickey}; # try to guess missing private key name + unless ($params->{ssh_privatekey} =~ s/\.pub$// and -r $params->{ssh_privatekey}) { + $logger->error("No ssh_privatekey specified or found to pair with " . $params->{ssh_publickey}); + return; + } + } + if ($params->{ssh_privatekey} and not $params->{ssh_publickey }) { + $params->{ssh_publickey} = $params->{ssh_privatekey} . '.pub'; # guess missing public key name + unless (-r $params->{ssh_publickey}) { + $logger->error("No ssh_publickey specified or found to pair with " . $params->{ssh_privatekey}); + return; + } + } + + # so now, we have either both ssh_p*key params or neither + foreach (qw/ssh_publickey ssh_privatekey/) { + unless (-r $params->{$_}) { + $logger->error("$_ '" . $params->{$_} . "' cannot be read: $!"); + return; # quit w/ error if we fail on any user-specified key + } + $keys{$params->{ssh_privatekey}} = $params->{ssh_publickey}; + } + return %keys; +} + sub handler { my $self = shift; my $env = shift; @@ -62,19 +148,67 @@ sub handler { return; } - my %options = (); - foreach (qw/debug type port/) { - $options{$_} = $params->{$_} if $params->{$_}; + my $text = $self->run_TT($env) or return; + my $tmp = File::Temp->new(); # magical self-destructing tempfile + print $tmp $text; + $logger->info("SendFile Reactor: using tempfile $tmp"); + + my %keys = (); + my $specific = 0; + my @put_args = ($tmp->filename); # same for scp_put and uFTP put + push @put_args, $params->{remote_file} if $params->{remote_file}; # user can specify remote_file name, optionally + + unless ($params->{type} and $params->{type} eq 'FTP') { + if ($params->{ssh_publickey} || $params->{ssh_privatekey}) { + $specific = 1; + %keys = param_keys($params) or return; # we got one or both params, but they didn't pan out + } else { + %keys = get_keyfiles(); # optional "force" arg could be used here to empty cache + } } - my $ftp = Net::uFTP->new($host, %options); + if (%keys) { + my $ssh2 = Net::SSH2->new(); + unless($ssh2->connect($host)) { + $logger->warn("SSH2 connect FAILED: $!" . join(" ", $ssh2->error)); + $specific and return; + %keys = (); # forget the keys, we cannot connect + } + foreach (keys %keys) { + my %auth_args = ( + privatekey => $_, + publickey => $keys{$_}, + rank => [qw/ publickey hostbased password /], + ); + $params->{remote_user } and $auth_args{username} = $params->{remote_user }; + $params->{remote_password} and $auth_args{password} = $params->{remote_password}; + $params->{remote_host } and $auth_args{hostname} = $params->{remote_host }; + + if ($ssh2->auth(%auth_args)) { + if ($ssh2->scp_put(@put_args)) { + $logger->info("SendFile Reactor: successfully sent ${host} " . join(' --> ', @put_args)); + return 1; + } else { + $logger->error("SendFile Reactor: put to $host failed with error: $!"); + return; + } + } elsif ($specific) { + $logger->error("Abort reactor: ssh2->auth FAILED for $host using $_: $!"); + return; + } else { + $logger->notice("Unsuccessful keypair: ssh2->auth FAILED for $host using $_: $!"); + } + } + } # my $conf = OpenSRF::Utils::SettingsClient->new; # $$env{something_hardcoded} = $conf->config_value('category', 'whatever'); - my $text = $self->run_TT($env) or return; - my $tmp = File::Temp->new(); # magical self-destructing tempfile - print $tmp $text; - $logger->info("SendFile Reactor: using tempfile $tmp"); + # Try w/ non-key uFTP methods + my %options = (); + foreach (qw/debug type port/) { + $options{$_} = $params->{$_} if $params->{$_}; + } + my $ftp = Net::uFTP->new($host, %options); my @login_args = (); foreach (qw/remote_user remote_password remote_account/) { @@ -85,16 +219,14 @@ sub handler { return; } - my @put_args = ($tmp); - push @put_args, $params->{remote_file} if $params->{remote_file}; # user can specify remote_file name, optionally my $filename = $ftp->put(@put_args); if ($filename) { - $logger->info("SendFile Reactor: successfully sent ${host} $filename"); + $logger->info("SendFile Reactor: successfully sent ${host} $tmp --> $filename"); return 1; + } else { + $logger->error("SendFile Reactor: put to $host failed with error: $!"); + return; } - - $logger->error("SendFile Reactor: put to $host failed with error: $!"); - return; } 1; -- 2.43.2