mjrrsh.pl

#!/usr/local/bin/perl

##
# @file      mjrrsh.pl
# @author    Mitch Richling <http://www.mitchr.me/>
# @Copyright Copyright 2003 by Mitch Richling.  All rights reserved.
# @brief     an rsh work alike@EOL
# @Keywords  perl TCP/IP rsh UNIX
# @Std       Perl5
#
#            Any UNIX admin that considers security at even the most
#            basic level should take a close look at a text that
#            describes basic TCP/IP protocols used for UNIX.  In
#            particular, any good UNIX admin should take a close look
#            at the protocols used by the "r"-commands.
#
#            This perl script is intended to illistrate just how
#            simple rsh(2) realy is.  Note, that the network protocol
#            simply has the user id and the command being sent to the
#            remote host.  Then the remote host sends the results
#            back.  Not a very good idea in our dangerous world.
#
#            The complexity in the script given is intended to provide
#            an example of how to make a perl script timeout and exit
#            gracefully even in the face of network protocols that can
#            just hang forever.  The script is a good basis for a
#            custom rsh that can be used as a more robust version than
#            the one supplied by most OS venders.  One can achieve the
#            same effect by putting an alarm in a perl script and
#            using the OS version of rsh.  The only disadvantage of
#            this approach is that the rsh can be left hanging around
#            from such a program.  By rolling your own version of rsh
#            in a perl script you can avoid shelling out, and you can
#            cleanly handle errors.  As an additional advantage, you
#            can take different actions based upon where in the script
#            the problem occurs.

use IO::Socket;

$DNSQTIMEOUT = 10;
$PINGTIMEOUT = 10;
$PORTTIMEOUT = 10;
$SENDTIMEOUT = 10;
$RECVTIMEOUT = 10;

if( ($< != 0) || ($> != 0) )  {
    print "Real or Effective UID is not 0\n"; 
    exit(1);
}

if( $#ARGV != 2) {
    die "Incorrect argument count.\n"; 
    exit(2);
}

$SIG{ALRM} = sub { print "Timeout during DNS lookup.\n"; exit(3); };
alarm $DNSQTIMEOUT;
if( ! gethostbyname($ARGV[1])) {
    print "Unknown host.  DNS lookup failed\n"; 
    exit(4);
}

$SIG{ALRM} = sub { print "Ping command hung.\n"; exit(5); };
alarm $PINGTIMEOUT;
if( !(`/usr/sbin/ping $ARGV[1] 1` =~ m/is alive/)) {
    print "Couldn't ping host.\n"; 
    exit(6);
}

$SIG{ALRM} = sub { print "Timeout obtaining a socket.\n"; exit(7); };
alarm $PORTTIMEOUT;
$tryPort = 1023;
$socket = 0;
while(($tryPort > 128) && (! $socket)) {
    $socket = IO::Socket::INET->new(PeerAddr => "$ARGV[1]",
                            PeerPort => 514,
                LocalPort => $tryPort,
                            Proto => "tcp",
                Type => SOCK_STREAM);
    $tryPort--;
}

if($socket) {
    $SIG{ALRM} = sub { print "Timeout sending command.\n"; exit(8); };
    alarm $SENDTIMEOUT;
    print $socket "\000$ARGV[0]\000$ARGV[0]\000$ARGV[2]\000";
    $SIG{ALRM} = sub { print "Timeout receving command output.\n"; exit(9); };
    alarm $RECVTIMEOUT;
    while(<$socket>) 
        { print "$_"; }
    close($socket);
    exit(0);
} else {
    print "Couldn't get socket\n";
    exit(10);
}

Generated by GNU enscript 1.6.4.