#!/usr/bin/perl #--------------------------------------------------------------------- # this is quite a hack. You may find it useful to set your tabstops # to 4. # # This script is designed to handle authentication requeusts from # Checkpoint's Firewall-1 firewall. I've only experienced the # behaviour in one environment, so I don't know what other # scenarios there are... # # in any case, this script waits for TCP connections on port 261, # and when on comes, it pops up a dialog window where the 6-digit # code from a SecurID card can be typed in. # # The PIN that belongs to the SecurID card can be entered when # the script is first started. This is, of course, less secure. # # you'll need perlTk for this... # # Rob Urban # #--------------------------------------------------------------------- use FileHandle; use Tk; use Socket; #use IO::Poll; #use Fcntl; BEGIN { $DEBUG = 0; $USER = 'firewall-user-name'; # FIX THIS $XUSER = 'local-user-name'; # FIX THIS $PIN = ''; $LOGFILE = '/var/log/fw-auth.log'; } openLog(); # get login dir of XUSER $login_dir = (getpwnam($XUSER))[7]; $DEBUG && print "login dir = [$login_dir]\n"; # set XAUTHORITY var $ENV{XAUTHORITY} = "$login_dir/.Xauthority"; getPIN(); #my $PORT = 3333; $PORT = 261; my $PROTO = getprotobyname('tcp'); socket(SERVER, PF_INET, SOCK_STREAM, $PROTO) || die "socket: $!"; setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; bind(SERVER, sockaddr_in($PORT, INADDR_ANY)) || die "bind: $!"; listen(SERVER, SOMAXCONN) || die "listen: $!"; logmsg("listener started on ".localtime); $SIG{CHLD} = \&REAPER; createDialog(); $TOP->after(50, [\&waitForConnection]); MainLoop; closeLog(); exit; #======================================================================== # subs #======================================================================== sub waitForConnection { $DEBUG && print "- entering waitForConnection() -\n"; my $paddr = accept(CLIENT, SERVER); $DEBUG && print "- after accept -\n"; my($port,$iaddr) = sockaddr_in($paddr); #my $name = gethostbyaddr($iaddr,AF_INET); logmsg("connection from ".inet_ntoa($iaddr)); #CLIENT->autoflush(1); select(CLIENT); $| = 1; select(STDOUT); handleConnection(); $DEBUG && print "- leaving waitForConnection() -\n"; } sub createDialog { $TOP = MainWindow->new; $TOP->withdraw; $DEBUG && print "after MainWindow...\n"; $TOP->wm(title => 'FW-1 Authentication'); #---------------------------------------------------- # label #---------------------------------------------------- my $lab = $TOP->Label(-text => "Authenticate user $USER"); $lab->pack(-side => 'top'); #---------------------------------------------------- # frame for entry + abort-button #---------------------------------------------------- my $f = $TOP->Frame->pack(-side => 'top'); #---------------------------------------------------- # entry #---------------------------------------------------- my $code_entry = $f->Entry( -width => 12, -textvariable => \$CODE, -show => '*', ); $code_entry->focus; $code_entry->bind('', sub { if ($SEND_CODE) { $DEBUG && print "sending code from binding.\n"; my $nwrite = syswrite(CLIENT, "$PIN$CODE\n"); $DEBUG && print "Wrote [$nwrite] bytes.\n"; $SEND_CODE = 0; } else { $DEBUG && print "send_code not set.\n"; } $HAVE_CODE = 1; } ); $code_entry->pack(-side => 'left'); #---------------------------------------------------- # abort-button #---------------------------------------------------- my $abort = $f->Button( -text => 'Abort', -command => [ \&closeConnection ], ); $abort->pack(-side => 'right'); #---------------------------------------------------- # message #---------------------------------------------------- my $msg = $TOP->Message( -text => '', -foreground => 'red', -relief => 'flat', -width => '6c', ); $msg->pack(-side => 'top'); sub message { my $m = shift; $msg->configure(-text => $m); $msg->after(3000, sub { $msg->configure(-text => ''); }); } $TOP->update; } sub closeConnection { $TOP->fileevent(CLIENT, 'readable', ''); # delete logmsg("closing connection\n"); close(CLIENT); $SEND_CODE = 0; $HAVE_CODE = 0; $CODE = ''; $TOP->after(50, [\&waitForConnection]); $DEBUG && print "- withdraw -\n"; $TOP->withdraw; } sub handleConnection { $DEBUG && print "in handleConnection()\n"; my $code; # bring up dialog box $DEBUG && print "- deiconify -\n"; $TOP->deiconify; $TOP->raise; $DEBUG && print "before fileevent...\n"; $TOP->fileevent(CLIENT, 'readable', sub { $DEBUG && print "- fileevent enter -\n"; my $nread = sysread(CLIENT, $_, 8192); if ($nread == 0) { $DEBUG && print "EOF\n"; closeConnection(); return; } #$DEBUG && dumpLine($_); s/[\n\r]*$//g; my @lines = split(/\n/, $_); $DEBUG && print "LINES:\n\t".join("\n\t", @lines)."\n"; foreach (@lines) { logmsg("SERVER: $_"); $DEBUG && print "LOOP: [$_]\n"; if (/^331 User:/) { $DEBUG && print "- matched 'user:' -\n"; my $nwrite = syswrite(CLIENT, "$USER\n"); $DEBUG && print "Wrote [$nwrite] bytes.\n"; $DEBUG && print "sent user-string\n"; logmsg('sent user-id'); } elsif (/^331 \*PASSCODE:/) { $DEBUG && print "- matched 'code:', waiting for enter -\n"; if ($HAVE_CODE) { $DEBUG && print "sending code from event-loop.\n"; $nwrite = syswrite(CLIENT, "$PIN$code\n"); $DEBUG && print "Wrote [$nwrite] bytes.\n"; logmsg('sent passcode'); $HAVE_CODE = 0; } else { $SEND_CODE = 1; } } elsif (/^331 \*next PASSCODE:/) { $code = ''; message('Enter Next CODE...'); $SEND_CODE = 1; } elsif (/^200 (.*)$/) { $LAST_RESPONSE = $1; } elsif (/^530 NOTOK/) { $DEBUG && print "got NOTOK.\n"; $code = ''; message('Authentication failed. Retry.'); logmsg("authentication failure: $LAST_RESPONSE"); $HAVE_CODE = 0; } elsif (/^230 OK/m) { $DEBUG && print "got OK.\n"; logmsg('authentication OK'); } $DEBUG && print "- fileevent leave -\n"; } }); $DEBUG && print "leaving handleConnection\n"; } sub openLog { $LOG_FH = FileHandle->new(">>$LOGFILE"); if (!defined($LOG_FH)) { die "open $LOGFILE for append"; } $LOG_FH->autoflush(1); } sub logmsg { my $msg = shift; print $LOG_FH "$msg\n"; } sub closeLog { $LOG_FH->close; } sub dumpLine { my $line = shift; foreach my $chr (split(//, $line)) { print '<'.ord($chr).'> '; } print "\n"; } sub getPIN { my $pin; my $mw = MainWindow->new; $mw->wm(title => 'Enter PIN'); my $lab = $mw->Label(-text => "enter PIN for user $USER"); $lab->pack(-side => 'top'); my $pin_entry = $mw->Entry( -width => 8, -textvariable => \$PIN, -show => '*', ); $pin_entry->focus; $pin_entry->pack(-side => 'top'); $pin_entry->bind('', sub { $DEBUG && print "PIN entered.\n"; $mw->destroy; } ); MainLoop; }