X-Git-Url: http://git.jankratochvil.net/?p=PerlMail.git;a=blobdiff_plain;f=perlmail-accept;h=e704077bce8d6a163b0e5cf34e23e6578c0d1fea;hp=f0586186a74496fe76cfd0a37446e4904de6dbf0;hb=0dd6e159920b9402e163cd35bdc8465dcfee65c9;hpb=e32c697b3f60065a62cec197b507d0557183fe8a;ds=sidebyside diff --git a/perlmail-accept b/perlmail-accept index f058618..e704077 100755 --- a/perlmail-accept +++ b/perlmail-accept @@ -46,6 +46,12 @@ INIT { use File::Basename; BEGIN { use lib $ENV{"PERLMAIL_BASEDIR"} || File::Basename::dirname($0); + + # FIXME: + use lib $ENV{"HOME"}."/lib64/perl5"; + use lib $ENV{"HOME"}."/lib/perl5"; + use lib $ENV{"HOME"}."/share/perl5"; + use PerlMail::Config; use PerlMail::Lib; } @@ -69,13 +75,13 @@ require HTTP::Request; require LWP::UserAgent; use URI::Escape 'uri_escape'; require WWW::SMS; -require Authen::SASL; # Sanity check for &Net::SMTP::auth +#require Authen::SASL; # Sanity check for &Net::SMTP::auth use MIME::Base64; use IPC::Open3; use POSIX ":sys_wait_h"; -our($Message,@AuditStored,$DoBell); +our($Message,@AuditStored,$DoBell,$Dry); my %alternates_host; # from @alternates_host my %dnsbl_whitelist; # from @dnsbl_whitelist @@ -92,7 +98,6 @@ $procmailFROM_MAILER=qr'^(((Resent-)?(From|Sender)|X-Envelope-From):|>?From )[^> my $opt_mode; my $opt_smstest; # 1 or $smscount my $opt_idle; -my $opt_dry; my $opt_single; @@ -125,8 +130,9 @@ sub inetd while (1) { local $/="\n"; + $!=undef(); my $length=; - confess "Unexpected EOF" if !defined $length; + confess "Unexpected EOF: $!" if !defined $length; confess "Missing EOL" if $length!~s/\n$//s; exit 0 if $length eq "BYE"; confess "Unrecognized length: $length" if $length!~/^\d+$/; @@ -386,7 +392,10 @@ my($name)=@_; die "Nesting profile: $name" if 0x10<=(local $profile_eval_depth=$profile_eval_depth+1); return @$name if ref $name; - die "Profile not found: $name" if !exists $audit_profile{$name}; + if (!exists $audit_profile{$name}) { + cluck "Profile not found: $name"; + return "did"; + } my @this=@{$audit_profile{$name}}; return (profile_eval($'),@this[1..$#this]) if $this[0] && $this[0]=~/^=/; return @this; @@ -421,15 +430,15 @@ my($folder,$profile,%args)=@_; $profile=$store_profile if !$profile; my %do=map({ (!/=/ ? ($_=>1) : ($`=>$')); } profile_eval($profile)); Sys::Syslog::syslog("info","%s%s%s: %s: %s", - (!$opt_dry ? "" : "--dry: "), + (!$Dry ? "" : "--dry: "), (!$store_ignore ? "" : "IGNORED[$store_ignore]: "), map({ cut($_); } $folder,address_show(unmime($Audit->from())),unmime($Audit->subject())), ) - if $do{"syslog"} || $opt_dry; + if $do{"syslog"} || $Dry; $folder=~s/;.*$//s; $folder="$Mail/".$' if $folder=~/^=/; push @AuditStored,$folder if $do{"did"}; - return if $store_ignore || $opt_dry; + return if $store_ignore || $Dry; $DoBell++ if $do{"bell"}; write_message($folder) or die; smssend_tryall $store_ignorenewmail,$do{"sms"},%args if $do{"sms"}; @@ -449,17 +458,28 @@ my($funcref,@funcargs)=@_; return @AuditStored!=$did_last; } +sub writeto +{ +my($filename)=@_; + + local *F; + open F,$filename or confess "open $filename: $!"; + print F $Message or confess "write $filename: $!"; + close F or confess "close $filename: $!"; + return 1; +} + # Never use Mail::Audit->store() as it will reformat MIME bodies and possibly corrupt OpenPGP! sub write_message { my($folder)=@_; - return 1 if $opt_dry; # simulate OK + return 1 if $Dry; # simulate OK local *F; open F,">>$folder" or do { warn "Append \"$folder\": $!"; return 0; }; { local $_; - ($_=Mail::Audit::audit_get_lock(\*F,$folder)) and do { warn "Lock \"$folder\": $!"; last; }; + ($_=$Audit->_audit_get_lock(\*F,$folder)) and do { warn "Lock \"$folder\": $!"; last; }; seek F,0,IO::Handle::SEEK_END or do { warn "Seek-end \"$folder\": $!"; last; }; # FIXME: Check for '^From ' to not to rely on our network peer print F $Message or do { warn "Write to \"$folder\": $!"; last; }; @@ -518,7 +538,8 @@ sub spamassassin { my($cmd)=@_; - $cmd||="spamassassin --exit-code 1"; + #$cmd||="nice spamassassin --exit-code 1 --mbox"; + $cmd||="spamc -c -s 50000000"; # spamassassin has the specified exit code if IS spam, code 0 if NOT spam # See &_spamchildcode for the code 1. local *CHILD; @@ -526,7 +547,11 @@ my($cmd)=@_; # prevent Razor2's: Can't call method "log" on unblessed reference at Razor2/Client/Agent.pm line 212. local $ENV{"HOME"}=$HOME; # 2>/dev/null to prevent error messages to corrupt inetd() output of perlmail-accept(1) - open CHILD,"|$cmd --mbox >/dev/null 2>/dev/null" + open CHILD,"|$cmd &>/dev/null" + # Workaround: spamassassin-3.1.3-1.fc5 + #.q{|awk '/^X-Spam-Flag: YES$/{if (!body) exit 1;}/^$/{body=1;}'} + # Original: + #." >/dev/null 2>/dev/null" or return 0; print CHILD $Message; close CHILD; @@ -556,7 +581,7 @@ sub dnsbl { my($domain,$full,$timeout)=@_; - $timeout||=30; # sec + $timeout||=2; # sec $Mail::Audit::MAPS::host=$domain; for my $host (Received_for()) { next if $host!~/^([^:@]*):/; @@ -564,15 +589,18 @@ my($domain,$full,$timeout)=@_; # $1 is DNS name, $ip is IP address next if $alternates_host{$1}; # leave only foreign hosts next if $dnsbl_whitelist{$ip}; - { - package My::Audit::Faked; - sub received { return @{$_[0]->{"received"}}; } - } - my $self_faked={ - "received"=>["[$ip]"], - }; - bless $self_faked,"My::Audit::Faked"; - my $code=Mail::Audit::rblcheck($self_faked,$timeout); + +# FIXME: Faking +# { +# package My::Audit::Faked; +# sub received { return @{$_[0]->{"received"}}; } +# } +# my $self_faked=Mail::Audit->new(); +# $self_faked->{"received"}=["[$ip]"]; +# bless $self_faked,"My::Audit::Faked"; +# my $code=Mail::Audit::rblcheck($self_faked,$timeout); + my $code=$Audit->rblcheck($timeout); + next if !$code; # Some 0.0.0.0 etc. found for , see: &Mail::Audit::MAPS::_checkit # Do not: $code!='1 Invalid IP address ' @@ -587,7 +615,7 @@ sub clamscan { my($cmd)=@_; - $cmd||='clamscan --no-summary -'; + $cmd||='nice clamscan --no-summary -'; # clamscan has exit code 1 if IS virus , code 0 if NOT virus # Do not use IPC::Open2 as it would try to use our STDERR which is not valid by: local *STDERR; local(*WR,*RD,*ERR); @@ -706,6 +734,7 @@ sub headeris { my($header,$string)=@_; + cluck if !defined $string; return _headercore(qr/\Q$string\E/i,1,$header,$string); } @@ -724,64 +753,6 @@ my($header,$map)=@_; $Audit->replace_header($header,$text); } -# LMTP engine: -use Net::Cmd qw(CMD_OK CMD_MORE); -{ - package My::Net::SMTP::LMTP; - require Net::SMTP; - our @ISA=qw(Net::SMTP); - use Net::SMTP; - use Net::Cmd qw(CMD_OK); - use Carp qw(confess cluck); - - # Do not: sub _HELO - # as it would not set {'net_smtp_esmtp'} - sub _EHLO { shift->command("LHLO", @_)->response() == CMD_OK } - - sub clucked - { - my($self,$func,@args)=@_; - - do { return $_ if defined $_; } for $self->$func(@args); - cluck $func; - return; - } -} - - -sub lmtp_deliver -{ -my($admin_user,$admin_pwd,$user_from,$user_to)=@_; - - my $lmtp=My::Net::SMTP::LMTP->clucked("new","localhost","Port"=>"lmtp", -# "Debug"=>1, - ) or return; - bless $lmtp,"My::Net::SMTP::LMTP"; -# Prevent: -# due to: -# $lmtp->auth(Authen::SASL->new( -# "mechanism"=>"PLAIN", -# "callback"=>{ -# "user"=>$admin_user, -# "pass"=>$admin_pwd, -# # Prevent: "authname"=>$admin_user -# # as it causes: DIE: Unknown callback: 'authname'. (user|auth|language|pass) -# })); - # FIXME: Authentication hack: - $lmtp->command("AUTH PLAIN")->response()==CMD_MORE - or do { cluck "auth announce"; return; }; - $lmtp->clucked("command",encode_base64($user_from."\x00".$admin_user."\x00".$admin_pwd)) or return; - $lmtp->clucked("mail",$user_from) or return; - $lmtp->clucked("to",$user_to) or return; - $lmtp->clucked("data"); # Do not: or return; - # Prevent: 554 5.6.0 Message contains invalid header - (my $data=$Message)=~s/\AFrom .*\r?\n//; - $lmtp->clucked("datasend",$data) or return; - $lmtp->clucked("dataend") or return; - $lmtp->clucked("quit") or return; -} - - # MAIN $Getopt::Long::ignorecase=0; @@ -789,7 +760,7 @@ die "GetOptions error" if !Getopt::Long::GetOptions( "inetd" ,sub { $opt_mode=\&inetd; }, "stdin" ,sub { $opt_mode=\&stdin; }, "single!" ,\$opt_single, - "dry" ,\$opt_dry, + "dry" ,\$Dry, "smstest:s",sub { $opt_mode=\&stdin; $opt_smstest=($_[1] || 1); }, "idle!" ,\$opt_idle, "idletest" ,sub { syslogging_restore(); print((defined($_=useridle()) ? $_ : "")."\n"); exit 0; },