[pm-h] Overriding package subroutines (the hard way)

Todd Rinaldo toddr at null.net
Fri Jul 6 06:19:43 PDT 2007


I went a little crazy yesterday (I was already partially there) trying to
figure this out. I thought I'd throw this out on the list and see if there
are other ways to do it.

We want to log a user's session to a priveliged account from start to stop.
We also need to do some pre-qual and some post processing once they're done.
We want to use Net::SSH::Perl to do this. Here's my problem: Net::SSH::Perl
has an interactive mode that would meet this need, except it does not
provide any obvious hooks to do additional logging. 

The bad way: Go re-write the appropriate pm file (Net::SSH::Pel::SSH2). I
refuse to use this option.

The evil way: Use Sub::Override to re-write the subroutine I want to hack.
The problem is it looks like this below. Search for ### in the override
code.

The problem with this code is it's not very adaptable to change if the CPAN
module changes. It'd be better if I could insert a hook and then have it
resume the original subroutine. I don't think I can with the Sub::Override
module. I've also got a problem with my use of main::LOG, but see no more
elegant way pull this off. 

Is there a better way? 

---------------------------------------------------------------------

#!perl

use strict;
use warnings;
use Net::SSH::Perl

package Net::SSH::Perl::SSH2;
use Sub::Override;
my $override = Sub::Override->new()

$override->replace (shell => sub {
    my $ssh = shift;
    my $cmgr = $ssh->channel_mgr;
    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));

    $channel->register_handler("_output_buffer", sub {
        syswrite STDOUT, $_[1]->bytes;

	  ############# Inserting custom TODD code.
	  my $output = $_[1]->bytes;
	  print main::LOG $output;
    });
    $channel->register_handler("_extended_buffer", sub {
        syswrite STDERR, $_[1]->bytes;
    });

    $ssh->debug("Entering interactive session.");
    $ssh->client_loop;
});
1;

# Must use package main to be able to write code after a package definition?
package main;

open (LOG, ">", "ssh.$$.log") or die;

use Net::SSH::Perl;
my $host = "host";
my $user = "username";
my $password = "passhere";

my $ssh = Net::SSH::Perl->new($host);
$ssh->login($user, $pass);

use Term::ReadKey;
ReadMode('raw');
$ssh->shell;
ReadMode('restore');

exit;



More information about the Houston mailing list