[Mimedefang] stream_by_... and invalid users

John Nemeth jnemeth at victoria.tc.ca
Fri Oct 10 05:29:01 EDT 2003


     I'm running MIMEDefang 2.37 with sendmail 8.12.10 on Solaris 8.
There is a problem with the stream_by_... functions and invalid users.
I ran some tests by telneting to my SMTP port and injecting several
test messages.  For the first, I specified two invalid users.  This was
completely rejected as expected.

     For the second test, I specified an invalid return address with a
valid domain, <blah2 at cornerstoneservice.ca>, a valid recipient and an
invalid recipient.  sendmail gave me an error on the invalid recipient
as expected.  However, when MIMEDefang did stream_by_recipient(), it
generated a message for both recipients.  Why does it do this?  How
does MIMEDefang get the list of recipients?  Since sendmail is called
with '-odd' it didn't do any recipient checks and just queued the
message.  At the next queue run, the one with the valid recipient was
delivered.  sendmail created a bounce message for the invalid recipient
and attempted to deliver it.  Since that wasn't possible, it generated
a double-bounce and delivered it to postmaster (me).

     For the third message, I specified a sender host that doesn't have
a listening SMTP server, a valid recipient, and an invalid recipient.
The process went pretty much the same as above; however, the bounce for
the invalid recipient is sitting in the outbound mail queue waiting for
the "originating" system to answer, which it will never do, so a
double-bounce will be generated in five days.

     This is very bad.  One of the reason for using MIMEDefang is to
try to cut down on the amount of postmaster mail, not triple or
quadruple it!  Is there anything that can be done about this?  I
understand the desire to not have large delays in send_by_... by
allowing sendmail to fully process the message, but not doing any
processing is causing significant problems.

     Another problem is that qf* files in clientmqueue are renamed to
Qf*.  This showed up when I started doing stream_by_recipient() and is
related to viruses.  An analysis of my logs shows that the process is
stream_by_recipient() queues a message with -odd, a later queue run
attempts to deliver the message but can't due to the virus, it then
creates a bounce message and attempts to send it to the originator
which also fails due to the virus, and finally it creates a
double-bounce message and attempts to send it to postmaster which also
fails due to the virus.  After that, it gives up, renames the queue
file, leaving the message in clientmqueue, and logs an error.
MIMEDefang is supposed be discarding viruses that were resent instead
of rejecting them.  Included below is my mimedefang-filter sans
comments and default functions.  Any idea what is wrong here?  This is
clogging up my clientmqueue and consuming large amounts of space where
I didn't expect it do so which is causing other problems.

     Finally, I was getting authentication warnings due to 'defang'
setting the sender on messages that had been resent.  I eliminated
these by adding 'Tdefang' to /etc/mail/submit.cf .  Perhaps a note
should be added to the documentation for the stream_by_... functions
advising people to do this.


# -*- Perl -*-
#***********************************************************************
#
# mimedefang-filter
#
#***********************************************************************

$AdminAddress = 'postmaster at victoria.tc.ca';
$AdminName = "MIMEDefang Administrator";

$DaemonAddress = 'mimedefang at victoria.tc.ca';

$AddWarningsInline = 0;

md_graphdefang_log_enable('mail', 1);

# $MaxMIMEParts = 50;

#***********************************************************************
# Set various stupid things your mail client does below.
#***********************************************************************

$Stupidity{"flatten"} = 0;

$Stupidity{"NoMultipleInlines"} = 0;

#if ($Features{"SpamAssassin"}) {
#    spam_assassin_init()->compile_now(1) if defined(spam_assassin_init());
#
#    # If you want to use auto-whitelisting:
##   if (defined($SASpamTester)) {
##       use Mail::SpamAssassin::DBBasedAddrList;
##       my $awl = Mail::SpamAssassin::DBBasedAddrList->new();
##       $SASpamTester->set_persistent_address_list_factory($awl) if defined($awl);
##   }
#}

#***********************************************************************
# %PROCEDURE: filter_begin
#***********************************************************************
sub filter_begin () {
    # ALWAYS drop messages with suspicious chars in headers
    if ($SuspiciousCharsInHeaders) {
        md_graphdefang_log('suspicious_chars');
#	action_quarantine_entire_message("Message quarantined because of suspicious characters in headers");
#	# Do NOT allow message to reach recipient(s)
#	return action_discard();
	return action_bounce("Suspicious chars found in header - rejected");
    }

    if (stream_by_recipient()) {
        return;
    }
    delete_ip_validation_header();

    # Scan for viruses if any virus-scanners are installed
    my($code, $category, $action) = message_contains_virus();

    # Lower level of paranoia - only looks for actual viruses
    $FoundVirus = ($category eq "virus");

    if ($action eq "tempfail") {
	action_tempfail("Problem running virus-scanner");
	md_syslog('warning', "Problem running virus scanner: code=$code, category=$category, action=$action");
    }
}

#***********************************************************************
# %PROCEDURE: filter
#***********************************************************************
sub filter ($$$$) {
    my($entity, $fname, $ext, $type) = @_;

    return if message_rejected(); # Avoid unnecessary work

    # Block message/partial parts
#    if (lc($type) eq "message/partial") {
#        md_graphdefang_log('message/partial');
#	action_bounce("MIME type message/partial not accepted here");
#	return action_discard();
#    }

    # Virus scan
    if ($FoundVirus) {
	my($code, $category, $action);
	$VirusScannerMessages = "";
	($code, $category, $action) = entity_contains_virus($entity);
	# If you are more paranoid, change to: if ($action eq "quarantine") {
	if ($category eq "virus") {
            md_graphdefang_log('virus',$VirusName, $RelayAddr);

	    # Bounce the mail!
            if ($WasResent) {
                action_discard();
            } else {
	        action_bounce("Virus $VirusName found in mail - rejected");
            }

	    return;
	}
	if ($action eq "tempfail") {
	    action_tempfail("Problem running virus-scanner");
	    md_syslog('warning', "Problem running virus scanner: code=$code, category=$category, action=$action");
	}
    }

#    if (filter_bad_filename($entity)) {
#        md_graphdefang_log('bad_filename', $fname, $type);
#	return action_quarantine($entity, "An attachment named $fname was removed from this document as it\nconstituted a security hazard.  If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
#    }

    # eml is bad if it's not multipart
#    if (re_match($entity, '\.eml')) {
#        md_graphdefang_log('non_multipart');
#	return action_quarantine($entity, "A non-multipart attachment named $fname was removed from this document as it\nconstituted a security hazard.  If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
#    }
    # Clean up HTML if Anomy::HTMLCleaner is installed.
#    if ($Features{"HTMLCleaner"}) {
#	if ($type eq "text/html") {
#	    return anomy_clean_html($entity);
#	}
#    }

    return action_accept();
}

#***********************************************************************
# %PROCEDURE: filter_multipart
#***********************************************************************
sub filter_multipart ($$$$) {
    my($entity, $fname, $ext, $type) = @_;

#    if (filter_bad_filename($entity)) {
#        md_graphdefang_log('bad_filename', $fname, $type);
#	action_notify_administrator("A MULTIPART attachment of type $type, named $fname was dropped.\n");
#	return action_drop_with_warning("An attachment of type $type, named $fname was removed from this document as it\nconstituted a security hazard.  If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
#    }

    # eml is bad if it's not message/rfc822
#    if (re_match($entity, '\.eml') and ($type ne "message/rfc822")) {
#        md_graphdefang_log('non_rfc822',$fname);
#	return action_drop_with_warning("A non-message/rfc822 attachment named $fname was removed from this document as it\nconstituted a security hazard.  If you require this document, please contact\nthe sender and arrange an alternate means of receiving it.\n");
#    }

    # Block message/partial parts
#    if (lc($type) eq "message/partial") {
#        md_graphdefang_log('message/partial');
#	action_bounce("MIME type message/partial not accepted here");
#	return;
#    }

    return action_accept();
}


# If SpamAssassin found SPAM, append report.  We do it as a separate
# attachment of type text/plain
sub filter_end ($) {
    my($entity) = @_;

    # If you want quarantine reports, uncomment next line
    send_quarantine_notifications();

    # No sense doing any extra work
    return if message_rejected();

    # Spam checks if SpamAssassin is installed
#    if ($Features{"SpamAssassin"}) {
#	if (-s "./INPUTMSG" < 100*1024) {
#	    my($hits, $req, $names, $report) = spam_assassin_check();
#	    my($score);
#	    if ($hits < 40) {
#		$score = "*" x int($hits);
#	    } else {
#		$score = "*" x 40;
#	    }
#	    action_change_header("X-Spam-Score", "$hits ($score) $names");
#	    if ($hits >= $req) {
#                md_graphdefang_log('spam', $hits, $RelayAddr);
#
#		action_add_part($entity, "text/plain", "-suggest",
#		                "$report\n",
#				"SpamAssassinReport.txt", "inline");
#	    } else {
#		action_delete_header("X-Spam-Score");
#	    }
#	}
#    }

    # If you don't mind HTML mail, comment out the next line.
#    remove_redundant_html_parts($entity);

}

# DO NOT delete the next line, or Perl will complain.
1;




More information about the MIMEDefang mailing list