#!/usr/bin/perl -Tw

########################################################
# A finger daemon that replies bogus data and logs     #
# every finger request to a file.                      #
# Copyright by Michael Kummer			       #
# Distributed under the GPL                            #
########################################################

# NOTE: This version forks to handle multiple clients at the same time BUT take care!!! there is
# no limit yet, that means this service could be the target of a DoS attack.
# I'll manage this issue in the next version.
# It still logs all requests to STDOUT!
# Stay tuned!

# If you wanna merge your code pieces drop me a line and i'll verify it
# <frost@outfit.2y.net>

require 5.001;
use strict;
BEGIN { $ENV{PATH} = '/usr/ucb:/bin' }
use Socket;
use Carp;
use FileHandle;

sub spawn;
sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }

my $port = 79;
my $proto = getprotobyname('tcp');
socket(Finger, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
setsockopt(Finger, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die "setsockopt: $!";
bind(Finger, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
listen(Finger, SOMAXCONN) or die "listen: $!";

logmsg "Finger service started on port $port";

my $waitpid = 0;
my $paddr;

sub REAPER {
	$waitpid = wait;
	$SIG{CHLD} = \&REAPER;
	logmsg "reaped $waitpid" . ($? ? " with exit $?" : "");
}

$SIG{CHLD} = \&REAPER;

for ( ; $paddr = accept(Client, Finger); close Client) {

	my($port, $iaddr) = sockaddr_in($paddr);
	my $name = gethostbyaddr($iaddr, AF_INET);

	logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port";
	
	spawn sub {
		my $fUSER = <Client>;
		logmsg "finger request for user $fUSER";

		my $DATA_STRING = "Login: $fUSER Name: $fUSER Directory: /home/$fUSER\n Shell: /bin/sh\n Never logged in.\n No mail.\n No Plan.";
		print Client $DATA_STRING;
	};
}  

sub spawn {
	my $coderef = shift;

	unless (@_ ==0 && $coderef && ref($coderef) eq 'CODE') {
		confess "usage: spawn CODEREF";
	}

	my $pid;
	if (!defined($pid = fork)) {
		logmsg "cannot fork: $!";
		return;
	} elsif ($pid) {
		logmsg "begat $pid";
		return; # that's the parent
	} # else i'm the child - go spawn

	exit &$coderef();
}
	
