lightnin!rwsys!trsvax!utacfd.uta.edu!news.oc.com!lgc.com!cs.utexas.edu!uunet!usc!rpi!scott.skidmore.edu!psinntp!psinntp!internet!sbi!zeuswtc!cyclone!bet Mon Oct 5 20:51:14 CDT 1992
Article: 1056 of comp.lang.perl
Path: lightnin!rwsys!trsvax!utacfd.uta.edu!news.oc.com!lgc.com!cs.utexas.edu!uunet!usc!rpi!scott.skidmore.edu!psinntp!psinntp!internet!sbi!zeuswtc!cyclone!bet
From:
[email protected] (Bennett E. Todd @ Salomon Brothers Inc., NY )
Newsgroups: comp.lang.perl
#Subject: Re: a perl program which is run from inetd
Message-ID: <
[email protected]>
Date: 30 Sep 92 21:10:05 GMT
References: <
[email protected]> <
[email protected]>
Sender:
[email protected]
Organization: Salomon Brothers, Inc.
Lines: 223
Here's an example daemon. I continue to twiddle and tweak it periodically.
#/usr/bin/perl
# Location of hosts DBM database
$hosts = '/usr/local/etc/hosts';
# Smtpd: SMTP daemon
#
# Install with a line like so in /etc/inetd.conf:
# smtp stream tcp nowait root .../smtpd %A
# If we print anything, let's make it look like Internet goop.
$\="\r\n"; # output line delimiter
# Save hostname for a zillion messages; date is needed for mail header
$hostname=`hostname`;
chop $hostname;
$date = `date`;
chop $date;
# Parse arg. The %A above cause $ARGV[0] to be something like 810e5850.2569
$ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
$o1 = hex($1);
$ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
$o2 = hex($1);
$ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
$o3 = hex($1);
$ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
$o4 = hex($1);
$ARGV[0] =~ s/^\.([0-9][0-9][0-9][0-9])// || die "500 bad address\r\n221 $hostname stopped";
$port = $1;
$via="$o1.$o2.$o3.$o4";
# Try to translate ``via'' IP address into hostname. Don't sweat it if you can't.
#open(HOSTS,'</etc/hosts') || die "500 cannot open /etc/hosts\r\n221 $hostname stopped";
#lookup: while (<HOSTS>) {
# /^$via[ ]*([^ ]*)/ && do { $via=$1; last lookup;};
#};
#close(HOSTS) || die "500 cannot close /etc/hosts\r\n221 $hostname stopped";
dbmopen(%hosts,$hosts,undef) && do {
($_ = $hosts{$via}) && ($via = $_);
dbmclose(%hosts);
};
# Suck up passwd file. There are other ways this could be implemented....
open(PASSWD, '</etc/passwd') || die "500 cannot open /etc/passwd\r\n221 $hostname stopped";
while(<PASSWD>) {
chop;
($pw_logname, $pw_passwd, $pw_uid, $pw_gid, $pw_gcos, $pw_home, $pw_shell) = split(/:/);
$pw_passwd{$pw_logname} = $pw_passwd;
$pw_uid{$pw_logname} = $pw_uid;
$pw_gid{$pw_logname} = $pw_gid;
$pw_gcos{$pw_logname} = $pw_gcos;
$pw_home{$pw_logname} = $pw_home;
if ($pw_shell eq '') {
$pw_shell{$pw_logname} = '/bin/sh';
} else {
$pw_shell{$pw_logname} = $pw_shell;
};
};
# Prepare for dialogue.
$|=1; # Unbuffered writes
$/="\r\n"; # input line delimiter
# Opening greetings
print "220 $hostname Smtpd";
# This is the SMTP protocol, deduced by experimenting against a sendmail.
# Sure, I could have busted it up into subroutines. With lables on the blocks
# I think this is just as clear. It is certainly one hell of a big loop, though.
parse_command: while (<STDIN>) {
chop;chop;
/^helo *(.*)/i && do {
$claim=$1;
print "250 $hostname Hello $claim ($via), pleased to meet you";
next parse_command;
};
/^help$/i && do {
print '214-Commands:';
print '214- HELO MAIL RCPT DATA RSET';
print '214- NOOP QUIT HELP VRFY EXPN';
print '214-For more info use "HELP <topic>".';
print '214-smtp';
print '214-Report bugs in the implementation to Bent.';
print '214 End of HELP info';
next parse_command;
};
s/^help *(.*)/\1/i && do {
helpswitch: {
/helo/i && do {
print '214-HELO <hostname>';
print '214- Introduce yourself. I am a boor, so I really don\'t';
print '214- care if you do.';
last helpswitch;
};
/mail/i && do {
print '214-MAIL FROM: <sender>';
print '214- Specifies the sender.';
last helpswitch;
};
/rcpt/i && do {
print '214-RCPT TO: <recipient>';
print '214- Specifies the recipient. Can be used any number of times.';
last helpswitch;
};
/data/i && do {
print '214-DATA';
print '214- Following text is collected as the message.';
print '214- End with a single dot.';
last helpswitch;
};
/rset/i && do {
print '214-RSET';
print '214- Resets the system.';
last helpswitch;
};
/noop/i && do {
print '214-NOOP';
print '214- Do nothing.';
last helpswitch;
};
/quit/i && do {
print '214-QUIT';
print '214- Exit smtpd (SMTP).';
last helpswitch;
};
/help/i && do {
print '214-HELP [ <topic> ]';
print '214- The HELP command gives help info.';
last helpswitch;
};
/vrfy/i && do {
print '214-VRFY <recipient>';
print '214- Not implemented to protocol. Gives some sexy';
print '214- information.';
last helpswitch;
};
/expn/i && do {
print '214-EXPN <recipient>';
print '214- Same as VRFY in this implementation.';
last helpswitch;
};
print '504 HELP topic unknown';
next parse_command;
};
print '214 End of HELP info';
next parse_command;
};
/^mail from: *(.*)/i && do {
$from=$1;
print "250 $from... Sender ok";
next parse_command;
};
/^noop/ && do {
print "200 OK";
next parse_command;
};
/^quit/i && do {
print "221 $hostname closing connection";
exit(0);
};
/^rset/i && do {
print '250 Reset state';
next parse_command;
};
s/^(vrfy|expn) *(.*)/\2/i && do {
s/@$hostname//;
if ($pw_uid{$_} eq '') {
print "550 $_... User unknown";
next parse_command;
};
print "250 $pw_gcos{$_} <$_>";
next parse_command;
};
s/^rcpt to: *(.*)/\1/i && do {
s/^.*<([^>]*)>.*$/\1/;
s/@$hostname//;
if ($pw_uid{$_} eq '') {
print "550 $_... User unknown";
next parse_command;
};
push(@recipients,$_);
print "250 $_... Recipient ok";
next parse_command;
};
/^data/i && do {
if ($from eq '') {
print '503 Need MAIL command';
next parse_command;
};
if ($#recipients < 0) {
print '503 Need RCPT (recipient)';
next parse_command;
}
open(BINMAIL,"|/bin/mail @recipients") || die "500 cannot call /bin/mail\r\n221 $hostname stopped";
$sender = $from;
$sender =~ s/^.*<([^>]*)>.*$/\1/;
$sender =~ s/@.*$//;
print BINMAIL "From $sender $date" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
print BINMAIL "From: $from" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
print BINMAIL "Received: $via ($claim)" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
print BINMAIL "To: @recipients" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
print '354 Enter mail, end with "." on a line by itself';
while (<STDIN>) {
chop;chop;
/^\.$/ && do {
close BINMAIL || die "500 cannot close /bin/mail pipe\r\n221 $hostname stopped";
print '250 Mail accepted';
$#recipients = 0;
$from = '';
next parse_command;
};
print BINMAIL || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
}
close BINMAIL;
exit 0;
};
print "500 Command unrecognized";
};