#!/usr/bin/perl # Murty's Mail Daemon version 1.0 # (c) Murty Rompalli 9/30/2001 # All rights reserved use Socket ; $| = 1 ; ######### Define User Variables $port = 25 ; $host = 'HOSTNAME' ; $iport = 26 ; $ihost = 'localhost' ; $filter = 'filter.txt' ; $log = 'log' ; $uid = $gid = 99 ; # This program runs as nobody:nobody ######### End of User Variables. Do not modify below this line. $host .= ' mmail' ; $paddr = sockaddr_in($iport, inet_aton($ihost)); $proto = getprotobyname('tcp') || 6 ; $SIG{CHLD} = 'IGNORE' ; $SIG{INT} = \&CLOSE ; -f $filter or die "$filter: No such file" ; -r $filter or die "$filter: Cannot read" ; -f $log or die "Error: $log must exist and be writable by $uid:$gid" ; &startserver ; for ($client = 'aaaa'; accept($client,Server) ; close $client++) { &handle unless fork ; } ## End of Main sub interact { print "220 $host SMTP Ready\r\n" ; while ($x = <$client>) { if ($error > 4) { print "550 Too many errors\r\n" ; return 1 ; } if ($data) { undef $data if ($x eq ".\r\n" || $x eq "." || $x eq ".\n") ; my $result = &processdata($x) ; if($result != '') { if($result =~ /^5/) { print "550 Error occurred.\r\n" ; return 1 ; } else { print "250 Message Accepted.\r\n" ; } } } else { chomp $x ; if($x =~ /\r$/) { chop $x ; } if ($x =~ /^HELO\s+(.+)/i) { if($helo) { $error++ ; print "503 You already Said HELO\r\n" ; } else { $helo = $1 ; my $result = &processhelo($helo) ; if($result !~ /^5/) { print "250 Hi There\r\n" ; } else { print "550 Connection Denied\r\n" ; return 1 ; } } } elsif ($x =~ /^MAIL\s+FROM:\s*(.+@.+)/i) { if($helo) { if($mail) { $error++ ; print "503 You already Said MAIL\r\n" ; } else { $mail = $1 ; my $mailraw = $mail ; if($mail =~ //) { ($mail) = $mail =~ /<(.+)>/ ; } $mail =~ s/\s*//g ; my $result = &processfrom($mailraw) ; if($result !~ /^5/) { print "250 Sender appears Ok\r\n" ; } else { $error++ ; print "550 Sender Blocked\r\n" ; return 1 ; } } } else { $error++ ; print "503 Say Helo First\r\n" ; } } elsif ($x =~ /^RCPT\s+TO:\s*(.+@.+)/i) { if ($helo && $mail) { my $toad = $1 ; my $toadraw = $toad ; if($toad =~ //) { ($toad) = $toad =~ /<(.+)>/ ; } $toad =~ s/\s*//g ; my $result = &processto($mail,$toad,$toadraw) ; if($result !~ /^5/) { @to = (@to,$toadraw) ; print "250 Recipient appears Ok\r\n" ; } elsif($result eq '5xx') { print "503 Type Email Address in Netscape/Internet Explorer\r\n" ; } else { $error++ ; print "550 Recipient Blocked\r\n" ; } } else { $error++ ; print "503 You forgot either HELO or MAIL\r\n" ; } } elsif ($x =~ /^DATA/i) { if($helo && $mail && @to) { my $datacmd = &processdatacmd($x) ; if($datacmd =~ /^5/) { print "550 Data not acceptable\r\n" ; $error++ ; } else { $data = 1 ; print "354 Proceed. End with a . on a line by itself\r\n" ; } } else { $error++ ; print "503 You didn't give all of HELO/MAIL/RCPT\r\n" ; } } elsif ($x =~ /QUIT/i || $x =~ /BYE/i) { print "221 Keep in touch\r\n" ; return 1 ; } elsif ($x =~ /RSET/i || $x =~ /RESET/i) { undef $helo ; undef $mail ; undef $data ; undef @to ; print "250 Reset Done\r\n" ; } else { $error++ ; print "500 Unknown Command\r\n" ; } } } } sub connectsmtp { socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!"; connect(SOCK, $paddr) || die "Error: connecting to $ihost:$iport" ; select SOCK ; $| = 1 ; return ; } sub closesmtp { print SOCK "QUIT\r\n" ; } sub startserver { socket(Server, PF_INET, SOCK_STREAM, $proto) || die "socket: $!" ; setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1) || die "setsockopt: $!" ; bind(Server, sockaddr_in($port, INADDR_ANY)) || die "bind: $!" ; listen(Server,SOMAXCONN) || die "listen: $!" ; ($>,$))=($uid,$gid); ($<,$()=($uid,$gid); } sub CLOSE { close Server ; close $client; close FH ; &closesmtp ; close SOCK ; # $SIG{INT} = \&CLOSE ; die 'Exiting on INT'; } sub handle { &openlog ; my $connect = &connectsmtp ; select $client ; $| = 1 ; if($connect !~ /^2/) { print "550 Connection Refused\r\n" ; } else { &interact ; } &closesmtp ; close SOCK ; close $client ; &closelog ; exit ; } sub processhelo { print SOCK "HELO ", $_[0], "\r\n" ; return ; } sub processfrom { print SOCK "MAIL FROM:", $_[0], "\r\n" ; return ; } sub processto { my ($sen,$rec,$recipient) = @_ ; my $result = &filter($sen,$rec) ; if ($result == 1) { print SOCK "RCPT TO:", $recipient, "\r\n" ; return ; } else { return '5xx' ; } } sub filter { my ($sen,$rec) = @_ ; my ($sendom) = $sen =~ /.+(@.+)/ ; my ($recdom) = $rec =~ /.+(@.+)/ ; my ($dline,$uline) ; my ($allowed,$dneg,$uneg) = (1,0,0) ; open(FH,"<$filter") or die "Error: opening filter" ; while() { my $j = $_ ; next unless ($j =~ /^-/ || $j =~ /^\w/ || $j =~ /^@/) ; if ($j =~ /^$recdom/i) { $dline = $j ; last if ($uline) ; } elsif ($j =~ /^-$recdom/i) { $j =~ s/^-// ; $dline = $j ; $dneg = 1 ; last if ($uline) ; } elsif ($j =~ /^$rec/i) { $uline = $j ; last if ($dline) ; } elsif ($j =~ /^-$rec/i) { $j =~ s/^-// ; $uline = $j ; $uneg = 1 ; last if ($dline) ; } } close FH ; if ($dline) { $dline .= ' ' ; if ($dline =~ /\s$sen\s/i || $dline =~ /\s$sendom\s/i) { if ($dneg) { $allowed = -1 ; } else { $allowed = 1 ; } } } if ($uline) { $uline .= ' ' ; if ($uline =~ /\s$sen\s/i || $uline =~ /\s$sendom\s/i) { if ($dneg) { $allowed = -1 ; } else { $allowed = 1 ; } } } return $allowed ; } sub processdata { #print SOCK $_[0], "\r\n" ; print SOCK $_[0] ; ($data) ? return '' : return ; } sub processdatacmd { print SOCK $_[0],"\r\n" ; return ; } sub printlog { print LOG join(' ',@_),"\n" ; } sub openlog { open(LOG,">>$log") || die "Error: writing to logfile $log" ; select LOG ; $| = 1 ; } sub closelog { close LOG || die "Error: closing logfile $log" ; }