X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=SSH.pm;h=3ac404c1c1d6c702384c05028f975004ac1ae868;hb=0798f662ba9aa6213688be0e49d2367af9c9fa09;hp=d3a8c22b5604fc27ad158cfee4551b079b140496;hpb=dbcc8ef3a679058ca47a3b994c6a488c14870bd6;p=Net-SSH.git diff --git a/SSH.pm b/SSH.pm index d3a8c22..3ac404c 100644 --- a/SSH.pm +++ b/SSH.pm @@ -1,15 +1,17 @@ package Net::SSH; use strict; -use vars qw($VERSION @ISA @EXPORT_OK $ssh $equalspace $DEBUG); +use vars qw($VERSION @ISA @EXPORT_OK $ssh $equalspace $DEBUG @ssh_options); use Exporter; +use POSIX ":sys_wait_h"; use IO::File; +use IO::Select; use IPC::Open2; use IPC::Open3; @ISA = qw(Exporter); @EXPORT_OK = qw( ssh issh ssh_cmd sshopen2 sshopen3 ); -$VERSION = '0.06'; +$VERSION = '0.08'; $DEBUG = 0; @@ -59,8 +61,8 @@ Calls ssh in batch mode. sub ssh { my($host, @command) = @_; - &_check_ssh_version unless defined $equalspace; - my @cmd = ($ssh, '-o', 'BatchMode'.$equalspace.'yes', $host, @command); + @ssh_options = &_ssh_options unless @ssh_options; + my @cmd = ($ssh, @ssh_options, $host, @command); warn "[Net::SSH::ssh] executing ". join(' ', @cmd). "\n" if $DEBUG; system(@cmd); @@ -107,7 +109,7 @@ sub ssh_cmd { $host = $opt->{user}. '@'. $host if exists $opt->{user}; @command = ( $opt->{command} ); push @command, @{ $opt->{args} } if exists $opt->{args}; - my $stdin_string = $opt->{stdin_string}; + $stdin_string = $opt->{stdin_string}; } else { ($host, @command) = @_; undef $stdin_string; @@ -117,19 +119,38 @@ sub ssh_cmd { my $writer = IO::File->new(); my $error = IO::File->new(); - sshopen3( $host, $writer, $reader, $error, @command ) or die $!; + my $pid = sshopen3( $host, $writer, $reader, $error, @command ) or die $!; print $writer $stdin_string if defined $stdin_string; close $writer; - local $/ = undef; - my $output_stream = <$reader>; - my $error_stream = <$error>; + my $select = new IO::Select; + foreach ( $reader, $error ) { $select->add($_); } + + my($output_stream, $error_stream) = ('', ''); + while ( $select->count ) { + my @handles = $select->can_read; + foreach my $handle ( @handles ) { + my $buffer = ''; + my $bytes = sysread($handle, $buffer, 4096); + if ( !defined($bytes) ) { + waitpid($pid, WNOHANG); + die "[Net::SSH::ssh_cmd] $!" + }; + $select->remove($handle) if !$bytes; + if ( $handle eq $reader ) { + $output_stream .= $buffer; + } elsif ( $handle eq $error ) { + $error_stream .= $buffer; + } + } - if ( length $error_stream ) { - die "[Net:SSH::ssh_cmd] STDERR $error_stream"; } + waitpid($pid, WNOHANG); + + die "$error_stream" if length($error_stream); + return $output_stream; } @@ -142,8 +163,8 @@ Connects the supplied filehandles to the ssh process (in batch mode). sub sshopen2 { my($host, $reader, $writer, @command) = @_; - &_check_ssh_version unless defined $equalspace; - open2($reader, $writer, $ssh, '-o', 'BatchMode'.$equalspace.'yes', $host, @command); + @ssh_options = &_ssh_options unless @ssh_options; + open2($reader, $writer, $ssh, @ssh_options, $host, @command); } =item sshopen3 HOST, WRITER, READER, ERROR, COMMAND [, ARGS ... ] @@ -154,8 +175,8 @@ Connects the supplied filehandles to the ssh process (in batch mode). sub sshopen3 { my($host, $writer, $reader, $error, @command) = @_; - &_check_ssh_version unless defined $equalspace; - open3($writer, $reader, $error, $ssh, '-o', 'BatchMode'.$equalspace.'yes', $host, @command); + @ssh_options = &_ssh_options unless @ssh_options; + open3($writer, $reader, $error, $ssh, @ssh_options, $host, @command); } sub _yesno { @@ -164,7 +185,7 @@ sub _yesno { $x =~ /^y/i; } -sub _check_ssh_version { +sub _ssh_options { my $reader = IO::File->new(); my $writer = IO::File->new(); my $error = IO::File->new(); @@ -176,6 +197,11 @@ sub _check_ssh_version { } else { $equalspace = "="; } + my @options = ( '-o', 'BatchMode'.$equalspace.'yes' ); + if ( $ssh_version =~ /.*OpenSSH[-|_](\w+)\./ && $1 > 1 ) { + unshift @options, '-T'; + } + @options; } =back @@ -204,17 +230,72 @@ sub _check_ssh_version { Q: How do you supply a password to connect with ssh within a perl script using the Net::SSH module? -A: You don't. Use RSA or DSA keys. See the ssh-keygen(1) manpage. +A: You don't (at least not with this module). Use RSA or DSA keys. See the + quick help in the next section and the ssh-keygen(1) manpage. + +A #2: See L instead. Q: My script is "leaking" ssh processes. A: See L, L, L and L. +=head1 GENERATING AND USING SSH KEYS + +=over 4 + +=item 1 Generate keys + +Type: + + ssh-keygen -t rsa + +And do not enter a passphrase unless you wanted to be prompted for +one during file copying. + +Here is what you will see: + + $ ssh-keygen -t rsa + Generating public/private rsa key pair. + Enter file in which to save the key (/home/User/.ssh/id_rsa): + Enter passphrase (empty for no passphrase): + + Enter same passphrase again: + + Your identification has been saved in /home/User/.ssh/id_rsa. + Your public key has been saved in /home/User/.ssh/id_rsa.pub. + The key fingerprint is: + 5a:cd:2b:0a:cd:d9:15:85:26:79:40:0c:55:2a:f4:23 User@JEFF-CPU + + +=item 2 Copy public to machines you want to upload to + +C is your public key. Copy it to C<~/.ssh> on target machine. + +Put a copy of the public key file on each machine you want to log into. +Name the copy C (some implementations name this file +C) + +Then type: + + chmod 600 authorized_keys + +Then make sure your home dir on the remote machine is not group or +world writeable. + +=back + =head1 AUTHORS Ivan Kohler +Assistance wanted - this module could really use a maintainer with enough time +to at least review and apply more patches. Or the module should just be +deprecated in favor of Net::SSH::Expect or made into an ::Any style +compatibility wrapper that uses whatver implementation is avaialble +(Net::SSH2, Net::SSH::Perl or shelling out like the modules does now). Please +email Ivan if you are interested in helping. + John Harrison contributed an example for the documentation. Martin Langhoff contributed the ssh_cmd command, and @@ -223,10 +304,13 @@ Jeff Finucane updated it and took care of the 0.04 release. Anthony Awtrey contributed a fix for those still using OpenSSH v1. +Thanks to terrence brannon for the documentation in +the GENERATING AND USING SSH KEYS section. + =head1 COPYRIGHT -Copyright (c) 2002 Ivan Kohler. -Copyright (c) 2002 Freeside Internet Services, LLC +Copyright (c) 2004 Ivan Kohler. +Copyright (c) 2007 Freeside Internet Services, Inc. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -235,12 +319,21 @@ the same terms as Perl itself. Not OO. -Look at IPC::Session (also fsh) +Look at IPC::Session (also fsh, well now the native SSH "master mode" stuff) =head1 SEE ALSO -For an all-perl implementation that does not require the system B command, -see L instead. +For a perl implementation that does not require the system B command, see +L instead. + +For a wrapper version that allows you to use passwords, see L +instead. + +For another non-forking version that uses the libssh2 library, see +L. + +For a way to execute remote Perl code over an ssh connection see +L. ssh-keygen(1), ssh(1), L, L, L