home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #18 / NN_1992_18.iso / spool / comp / lang / perl / 5427 < prev    next >
Encoding:
Internet Message Format  |  1992-08-21  |  6.6 KB

  1. Path: sparky!uunet!zaphod.mps.ohio-state.edu!rpi!scott.skidmore.edu!psinntp!psinntp!internet!sbi!zeuswtc!cyclone!bet
  2. From: bet@cyclone.sbi.com (Bennett E. Todd)
  3. Newsgroups: comp.lang.perl
  4. Subject: SMTP daemon in perl
  5. Message-ID: <707@cyclone.sbi.com>
  6. Date: 21 Aug 92 03:24:12 GMT
  7. Organization: Salomon Brothers, Inc
  8. Lines: 217
  9.  
  10.  
  11. A little doodad I whacked out one evening. I've yet to write a real gung-ho
  12. replacement for the local-delivery part of sendmail, so this isn't quite
  13. complete yet, but it was kinda fun.
  14.  
  15. -Bennett
  16. bet@sbi.com
  17.  
  18.  
  19. #!/usr/bin/perl
  20.  
  21. # Smtpd: SMTP daemon
  22. #
  23. # Install with a line like so in /etc/inetd.conf:
  24. #  smtp stream tcp nowait root .../smtpd %A
  25.  
  26. # If we print anything, let's make it look like Internet goop.
  27. $\="\r\n"; # output line delimiter
  28.  
  29.  
  30. # Save hostname for a zillion messages
  31. $hostname=`hostname`;
  32. chop $hostname;
  33.  
  34. # Parse arg. The %A above cause $ARGV[0] to be something like 810e5850.2569
  35. $ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
  36. $o1 = hex($1);
  37. $ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
  38. $o2 = hex($1);
  39. $ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
  40. $o3 = hex($1);
  41. $ARGV[0] =~ s/^([0-9a-e][0-9a-e])// || die "500 bad address\r\n221 $hostname stopped";
  42. $o4 = hex($1);
  43. $ARGV[0] =~ s/^\.([0-9][0-9][0-9][0-9])// || die "500 bad address\r\n221 $hostname stopped";
  44. $port = $1;
  45. $via="$o1.$o2.$o3.$o4";
  46.  
  47. # Try to translate ``via'' IP address into hostname. Don't sweat it if you can't.
  48. open(HOSTS,'</etc/hosts') || die "500 cannot open /etc/hosts\r\n221 $hostname stopped";
  49. lookup: while (<HOSTS>) {
  50.     /^$via[     ]*([^     ]*)/ && do { $via=$1; last lookup;};
  51. };
  52. close(HOSTS) || die "500 cannot close /etc/hosts\r\n221 $hostname stopped";
  53.  
  54. # Suck up passwd file. There are other ways this could be implemented....
  55. open(PASSWD, '</etc/passwd') || die "500 cannot open /etc/passwd\r\n221 $hostname stopped";
  56. while(<PASSWD>) {
  57.     chop;
  58.     ($pw_logname, $pw_passwd, $pw_uid, $pw_gid, $pw_gcos, $pw_home, $pw_shell) = split(/:/);
  59.     $pw_passwd{$pw_logname} = $pw_passwd;
  60.     $pw_uid{$pw_logname} = $pw_uid;
  61.     $pw_gid{$pw_logname} = $pw_gid;
  62.     $pw_gcos{$pw_logname} = $pw_gcos;
  63.     $pw_home{$pw_logname} = $pw_home;
  64.     if ($pw_shell eq '') {
  65.         $pw_shell{$pw_logname} = '/bin/sh';
  66.     } else {
  67.         $pw_shell{$pw_logname} = $pw_shell;
  68.     };
  69. };
  70.  
  71. # Prepare for dialogue.
  72. $|=1;      # Unbuffered writes
  73. $/="\r\n"; # input line delimiter
  74.  
  75. # Opening greetings
  76. print "220 $hostname Smtpd";
  77.  
  78. # This is the SMTP protocol, deduced by experimenting against a sendmail.
  79. # Sure, I could have busted it up into subroutines. With lables on the blocks
  80. # I think this is just as clear. It is certainly one hell of a big loop, though.
  81. parse_command: while (<STDIN>) {
  82.     chop;chop;
  83.     /^helo *(.*)/i && do {
  84.         $claim=$1;
  85.         print "250 $hostname Hello $claim ($via), pleased to meet you";
  86.         next parse_command;
  87.     };
  88.     /^help$/i && do {
  89.         print '214-Commands:';
  90.         print '214-    HELO    MAIL    RCPT    DATA    RSET';
  91.         print '214-    NOOP    QUIT    HELP    VRFY    EXPN';
  92.         print '214-For more info use "HELP <topic>".';
  93.         print '214-smtp';
  94.         print '214-Report bugs in the implementation to Bent.';
  95.         print '214 End of HELP info';
  96.         next parse_command;
  97.     };
  98.     s/^help *(.*)/\1/i && do {
  99.       helpswitch: {
  100.         /helo/i && do {
  101.             print '214-HELO <hostname>';
  102.             print '214-    Introduce yourself.  I am a boor, so I really don\'t';
  103.             print '214-    care if you do.';
  104.             last helpswitch;
  105.         };
  106.         /mail/i && do {
  107.             print '214-MAIL FROM: <sender>';
  108.             print '214-    Specifies the sender.';
  109.             last helpswitch;
  110.         };
  111.         /rcpt/i && do {
  112.             print '214-RCPT TO: <recipient>';
  113.             print '214-    Specifies the recipient.  Can be used any number of times.';
  114.             last helpswitch;
  115.         };
  116.         /data/i && do {
  117.             print '214-DATA';
  118.             print '214-    Following text is collected as the message.';
  119.             print '214-    End with a single dot.';
  120.             last helpswitch;
  121.         };
  122.         /rset/i && do {
  123.             print '214-RSET';
  124.             print '214-    Resets the system.';
  125.             last helpswitch;
  126.         };
  127.         /noop/i && do {
  128.             print '214-NOOP';
  129.             print '214-    Do nothing.';
  130.             last helpswitch;
  131.         };
  132.         /quit/i && do {
  133.             print '214-QUIT';
  134.             print '214-    Exit smtpd (SMTP).';
  135.             last helpswitch;
  136.         };
  137.         /help/i && do {
  138.             print '214-HELP [ <topic> ]';
  139.             print '214-    The HELP command gives help info.';
  140.             last helpswitch;
  141.         };
  142.         /vrfy/i && do {
  143.             print '214-VRFY <recipient>';
  144.             print '214-    Not implemented to protocol.  Gives some sexy';
  145.             print '214-    information.';
  146.             last helpswitch;
  147.         };
  148.         /expn/i && do {
  149.             print '214-EXPN <recipient>';
  150.             print '214-    Same as VRFY in this implementation.';
  151.             last helpswitch;
  152.         };
  153.         print '504 HELP topic unknown';
  154.         next parse_command;
  155.       };
  156.       print '214 End of HELP info';
  157.       next parse_command;
  158.     };
  159.     /^mail from: *(.*)/i && do {
  160.         $from=$1;
  161.         print "250 $from... Sender ok";
  162.         next parse_command;
  163.     };
  164.     /^noop/ && do {
  165.         print "200 OK";
  166.         next parse_command;
  167.     };
  168.     /^quit/i && do {
  169.         print "221 $hostname closing connection";
  170.         exit(0);
  171.     };
  172.     /^rset/i && do {
  173.         print '250 Reset state';
  174.         next parse_command;
  175.     };
  176.     s/^(vrfy|expn) *(.*)/\2/i && do {
  177.         s/@$hostname//;
  178.         if ($pw_uid{$_} eq '') {
  179.             print "550 $_... User unknown";
  180.             next parse_command;
  181.         };
  182.         print "250 $pw_gcos{$_} <$_>";
  183.         next parse_command;
  184.     };
  185.     s/^rcpt to: *(.*)/\1/i && do {
  186.         s/@$hostname//;
  187.         if ($pw_uid{$_} eq '') {
  188.             print "550 $_... User unknown";
  189.             next parse_command;
  190.         };
  191.         push(@recipients,$_);
  192.         print "250 $_... Recipient ok";
  193.         next parse_command;
  194.     };
  195.     /^data/i && do {
  196.         if ($from eq '') {
  197.             print '503 Need MAIL command';
  198.             next parse_command;
  199.         };
  200.         if ($#recipients < 0) {
  201.             print '503 Need RCPT (recipient)';
  202.             next parse_command;
  203.         }
  204.         open(BINMAIL,"|/bin/mail @recipients") || die "500 cannot call /bin/mail\r\n221 $hostname stopped";
  205.         print BINMAIL "From $from\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  206.         print BINMAIL "From: $from\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  207.         print BINMAIL "Received-From: $via\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  208.         print BINMAIL "To: @recipients\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  209.         print BINMAIL "\n" || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  210.         print '354 Enter mail, end with "." on a line by itself';
  211.         while (<STDIN>) {
  212.             chop;chop;
  213.             /^\.$/ && do {
  214.                 close BINMAIL || die "500 cannot close /bin/mail pipe\r\n221 $hostname stopped";
  215.                 print '250 Mail accepted';
  216.                 $#recipients = 0;
  217.                 $from = '';
  218.                 next parse_command;
  219.             };
  220.             print BINMAIL || die "500 cannot send data to /bin/mail\r\n221 $hostname stopped";
  221.         }
  222.         close BINMAIL;
  223.         exit 0;
  224.     };
  225.     print "500 Command unrecognized";
  226. };
  227.