#!/usr/local/bin/perl -Tw


######################################################################
# Thomas P. Kelliher, Goucher College.  (c) 2000.
#
# This telnet, ssh, etc. replacement will send e-mail to $recipient.
# The e-mail will contain the IP address and, if possible, the FQDN
# of the client attempting the connection.  The contact information in
# $contact is returned to the client.
#
# The purpose of this script is to monitor connections to ports which
# shouldn't be receiving connections.
#
# We assume we're being called via inetd.  inetd.conf should be
# configured to run this as nobody, but we'll be paranoid and try
# to guarantee that.  If we're being run as root we'll change UID to
# nobdy.  So, this script assumes that there's a nobody user on the
# system.  This is true for BSD/OS, Solaris, and Linux.
#
# The inetd parent process will fork a child on connection.  The
# child closes all its descriptors, save for the socket, dups the
# socket to STDIN, STDOUT, and STDERR, and exec's the service handler
# (this program).  Thus the socket calls on STDIN below.  Also note
# this allows us to use standard I/O to communicate with the client.
#
# Some constants below need to be configured.  The shebang line may
# need to be modified.
######################################################################


use strict;
use Socket;


######################################################################
# Constants.  These need to be configured.
######################################################################

#Path to mail client.
my $mailPath = "/usr/bin/mail";

# Recipient of the e-mail.  Also part of contact information.
my $recipient = "kelliher\@bluebird.goucher.edu";

# Contact information.
my $contact = "   Tom Kelliher\r\n"
   . "   (410) 337-6189\r\n"
   . "   $recipient";

# How many seconds to sleep before exiting.
my $delay = 10;

# Index of UID field in a passwd file entry.
my $uidIndex = 2;

######################################################################
MAIN:
######################################################################

{
   # Port and IP address of either end of socket.
   my $port;
   my $ipaddr;

   my $rootUid;           # UID of root.
   my $nobodyUid = "";    # UID of nobody user.
   my $lsocket;           # Socket at this end.
   my $rsocket;           # Socket at remote end.
   my $host;              # FQDN.
   my $straddr;           # Remote IP address in ASCII.
   my $service;           # Local port contacted.

   $ENV{"PATH"} = "";   # Clean things up.

   # If we're running as root, change UIDs to nobody.
   $rootUid = (getpwnam("root"))[$uidIndex];
   if ($< == $rootUid)
   {
      $nobodyUid = (getpwnam("nobody"))[$uidIndex];
      $< = $nobodyUid;
   }

   # Get all relevant socket information.  If we're not connected to a
   # socket, just exit.
   if (!($lsocket = getsockname(STDIN)))
   {
      exit(1);
   }
   $rsocket = getpeername(STDIN);

   # Determine what local port we're on.
   ($port, $ipaddr) = unpack_sockaddr_in($lsocket);
   $service = getservbyport($port, "tcp") || "Port $port";

   # Get remote IP address and try to get a FQDN.
   ($port, $ipaddr) = unpack_sockaddr_in($rsocket);
   $host = gethostbyaddr($ipaddr, AF_INET)
      || "Could not reverse map IP address";
   $straddr = inet_ntoa($ipaddr);

   # Log connection via a piece of e-mail.
   open(MAIL,
        "|$mailPath -s \"$service connection\" $recipient");
   print MAIL "$service connection received from: $host [$straddr].\n";
   if ($nobodyUid)
   {
      print MAIL "\nThis script was running as root originally.\n"
   }
   close(MAIL);

   # If we're ssh, just quietly exit.
   if ($service eq "ssh")
   {
      exit(0);
   }

   # Unbuffer output and send contact information to remote client.
   $| = 1;
   print "\r\n\r\n", 
   "If you need access to this machine, please contact:\r\n\r\n",
   "$contact\r\n\r\n";

   # Give them some time to read it.
   sleep $delay;

   exit 0;
}
