package MySSH; use strict; use Net::SSH::Perl; use Net::SSH::Perl::SSH1; use Net::SSH::Perl::SSH2; use base qw(Net::SSH::Perl); { package Net::SSH::Perl::SSH1; sub scripted_shell { my($ssh,$skip_stdin) = @_; $ssh->{config}->set('use_pty', 1) unless defined $ssh->{config}->get('use_pty'); $ssh->_setup_connection; $ssh->debug("Requesting shell."); my $packet = $ssh->packet_start(SSH_CMSG_EXEC_SHELL); $packet->send; unless($ssh->handler_for(SSH_SMSG_STDOUT_DATA)) { $ssh->register_handler(SSH_SMSG_STDOUT_DATA, sub { syswrite STDOUT, $_[1]->get_str }); } unless($ssh->handler_for(SSH_SMSG_STDERR_DATA)) { $ssh->register_handler(SSH_SMSG_STDERR_DATA, sub { syswrite STDERR, $_[1]->get_str }); } unless($ssh->handler_for(SSH_SMSG_EXITSTATUS)) { $ssh->register_handler(SSH_SMSG_EXITSTATUS, sub {}); } $ssh->debug("Entering interactive session."); $ssh->_start_interactive($skip_stdin ? 1 : 0); $ssh->_disconnect; } } { package Net::SSH::Perl::SSH2; # disable dummy shell, pix/cisco can only handle one channel sub login { my $ssh = shift; $ssh->SUPER::login(@_); $ssh->_login or $ssh->fatal_disconnect("Permission denied"); $ssh->debug("Login completed"); return 1; } sub scripted_shell { my $ssh = shift; my $channel = $ssh->_session_channel; $channel->open; $channel->register_handler(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, sub { my($channel, $packet) = @_; my $r_packet = $channel->request_start('pty-req', 0); my($term) = $ENV{TERM} =~ /(\w+)/; $r_packet->put_str($term); $r_packet->put_int32(0) for 1..4; $r_packet->put_str(""); $r_packet->send; $channel->{ssh}->debug("Requesting shell."); $channel->request("shell", 0); }); my($exit); $channel->register_handler(SSH2_MSG_CHANNEL_REQUEST, _make_input_channel_req(\$exit)); my $h = $ssh->{client_handlers}; if (my $r = $h->{stdout}) { $channel->register_handler("_output_buffer", $r->{code}, @{ $r->{extra} }); } else { $channel->register_handler("_output_buffer", sub { syswrite STDOUT, $_[1]->bytes; }); } if (my $r = $h->{stderr}) { $channel->register_handler("_extended_buffer", $r->{code}, @{ $r->{extra} }); } else { $channel->register_handler("_extended_buffer", sub { syswrite STDERR, $_[1]->bytes; }); } $ssh->debug("Entering interactive session."); $ssh->client_loop; } # having no dummy channel means the open_channels check below changes sub client_loop { my $ssh = shift; my $cmgr = $ssh->channel_mgr; my $h = $cmgr->handlers; my $select_class = $ssh->select_class; CLOOP: $ssh->{_cl_quit_pending} = 0; while (!$ssh->_quit_pending) { while (my $packet = Net::SSH::Perl::Packet->read_poll($ssh)) { if (my $code = $h->{ $packet->type }) { $code->($cmgr, $packet); } else { $ssh->debug("Warning: ignore packet type " . $packet->type); } } if($ssh->_quit_pending){ $ssh->debug("client_loop: quit pending"); last; } $cmgr->process_output_packets; my $rb = $select_class->new; my $wb = $select_class->new; $rb->add($ssh->sock); $cmgr->prepare_channels($rb, $wb); #last unless $cmgr->any_open_channels; my $open_channels = grep { defined } @{ $cmgr->{channels} }; if($open_channels < 1) { $ssh->debug("client_loop: no more open channels, exiting"); last; } my($rready, $wready) = $select_class->select($rb, $wb); $cmgr->process_input_packets($rready, $wready); for my $a (@$rready) { if ($a == $ssh->{session}{sock}) { my $buf; my $len = sysread $a, $buf, 8192; $ssh->break_client_loop if $len == 0; ($buf) = $buf =~ /(.*)/s; ## Untaint data. Anything allowed. $ssh->incoming_data->append($buf); } } } } } 1;