package Net::SSH; use strict; use vars qw($VERSION @ISA @EXPORT_OK $ssh $equalspace $DEBUG); use Exporter; use IO::File; use IPC::Open2; use IPC::Open3; @ISA = qw(Exporter); @EXPORT_OK = qw( ssh issh ssh_cmd sshopen2 sshopen3 ); $VERSION = '0.06'; $DEBUG = 0; $ssh = "ssh"; =head1 NAME Net::SSH - Perl extension for secure shell =head1 SYNOPSIS use Net::SSH qw(ssh issh sshopen2 sshopen3); ssh('user@hostname', $command); issh('user@hostname', $command); ssh_cmd('user@hostname', $command); ssh_cmd( { user => 'user', host => 'host.name', command => 'command', args => [ '-arg1', '-arg2' ], stdin_string => "string\n", } ); sshopen2('user@hostname', $reader, $writer, $command); sshopen3('user@hostname', $writer, $reader, $error, $command); =head1 DESCRIPTION Simple wrappers around ssh commands. For an all-perl implementation that does not require the system B command, see L instead. =head1 SUBROUTINES =over 4 =item ssh [USER@]HOST, COMMAND [, ARGS ... ] Calls ssh in batch mode. =cut sub ssh { my($host, @command) = @_; &_check_ssh_version unless defined $equalspace; my @cmd = ($ssh, '-o', 'BatchMode'.$equalspace.'yes', $host, @command); warn "[Net::SSH::ssh] executing ". join(' ', @cmd). "\n" if $DEBUG; system(@cmd); } =item issh [USER@]HOST, COMMAND [, ARGS ... ] Prints the ssh command to be executed, waits for the user to confirm, and (optionally) executes the command. =cut sub issh { my($host, @command) = @_; my @cmd = ($ssh, $host, @command); print join(' ', @cmd), "\n"; if ( &_yesno ) { system(@cmd); } } =item ssh_cmd [USER@]HOST, COMMAND [, ARGS ... ] =item ssh_cmd OPTIONS_HASHREF Calls ssh in batch mode. Throws a fatal error if data occurs on the command's STDERR. Returns any data from the command's STDOUT. If using the hashref-style of passing arguments, possible keys are: user (optional) host (requried) command (required) args (optional, arrayref) stdin_string (optional) - written to the command's STDIN =cut sub ssh_cmd { my($host, $stdin_string, @command); if ( ref($_[0]) ) { my $opt = shift; $host = $opt->{host}; $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}; } else { ($host, @command) = @_; undef $stdin_string; } my $reader = IO::File->new(); my $writer = IO::File->new(); my $error = IO::File->new(); 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>; if ( length $error_stream ) { die "[Net:SSH::ssh_cmd] STDERR $error_stream"; } return $output_stream; } =item sshopen2 [USER@]HOST, READER, WRITER, COMMAND [, ARGS ... ] Connects the supplied filehandles to the ssh process (in batch mode). =cut sub sshopen2 { my($host, $reader, $writer, @command) = @_; &_check_ssh_version unless defined $equalspace; open2($reader, $writer, $ssh, '-o', 'BatchMode'.$equalspace.'yes', $host, @command); } =item sshopen3 HOST, WRITER, READER, ERROR, COMMAND [, ARGS ... ] Connects the supplied filehandles to the ssh process (in batch mode). =cut 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); } sub _yesno { print "Proceed [y/N]:"; my $x = scalar(); $x =~ /^y/i; } sub _check_ssh_version { my $reader = IO::File->new(); my $writer = IO::File->new(); my $error = IO::File->new(); open3($writer, $reader, $error, $ssh, '-V'); my $ssh_version = <$error>; chomp($ssh_version); $ssh_version =~ s/.*OpenSSH[-|_](\w+?)\.\w+?\.\w+?.*/$1/g; if ($ssh_version == 1) { $equalspace = " "; } else { $equalspace = "="; } } =back =head1 EXAMPLE use Net::SSH qw(sshopen2); use strict; my $user = "username"; my $host = "hostname"; my $cmd = "command"; sshopen2("$user\@$host", *READER, *WRITER, "$cmd") || die "ssh: $!"; while () { chomp(); print "$_\n"; } close(READER); close(WRITER); =head1 FREQUENTLY ASKED QUESTIONS 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. Q: My script is "leaking" ssh processes. A: See L, L, L and L. =head1 AUTHORS Ivan Kohler John Harrison contributed an example for the documentation. Martin Langhoff contributed the ssh_cmd command, and Jeff Finucane updated it and took care of the 0.04 release. Anthony Awtrey contributed a fix for those still using OpenSSH v1. =head1 COPYRIGHT Copyright (c) 2002 Ivan Kohler. Copyright (c) 2002 Freeside Internet Services, LLC All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 BUGS Not OO. Look at IPC::Session (also fsh) =head1 SEE ALSO For an all-perl implementation that does not require the system B command, see L instead. ssh-keygen(1), ssh(1), L, L, L =cut 1;