home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!zaphod.mps.ohio-state.edu!rpi!scott.skidmore.edu!psinntp!psinntp!internet!sbi!zeuswtc!cyclone!bet
- From: bet@cyclone.sbi.com (Bennett E. Todd)
- Newsgroups: comp.lang.perl
- Subject: SMTP daemon in perl
- Message-ID: <707@cyclone.sbi.com>
- Date: 21 Aug 92 03:24:12 GMT
- Organization: Salomon Brothers, Inc
- Lines: 217
-
-
- A little doodad I whacked out one evening. I've yet to write a real gung-ho
- replacement for the local-delivery part of sendmail, so this isn't quite
- complete yet, but it was kinda fun.
-
- -Bennett
- bet@sbi.com
-
-
- #!/usr/bin/perl
-
- # 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
- $hostname=`hostname`;
- chop $hostname;
-
- # 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";
-
- # 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/@$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";
- print BINMAIL "From $from\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
- print BINMAIL "From: $from\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
- print BINMAIL "Received-From: $via\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
- print BINMAIL "To: @recipients\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
- print BINMAIL "\n" || 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";
- };
-