[Mimedefang] Compliance

Jan Pieter Cornet johnpc at xs4all.nl
Thu Apr 7 18:46:10 EDT 2005


On Thu, Apr 07, 2005 at 04:58:28PM -0400, Joseph Brennan wrote:
> --On Thursday, April 7, 2005 22:30 +0200 Jan Pieter Cornet 
> <johnpc at xs4all.nl> wrote:
> 
> >We're not using it for any "compliance" testing (mainly because
> >we're an ISP), but we do use it for other things:
> >- rejecting on quota exceeded earlier than sendmail detects it
> 
> How are you checking quota?  Sounds interesting.

Using the perl interface to quotactl, the Quota module. The big
advantage of this is that we are able to reject at the SMTP level,
based on quota, instead of having mail.local detect the out of
quota condition, and then bounce it. This saves us on average
about 4 or 5 bounces per second (with peaks to more than 10/sec
during some spam runs).

Our current module used to check quotas is a bit messy and uses
a few hardcoded local configurations, but should otherwise be
reasonably usable... 

I'll paste a summary of our current logic. You'll have to fill in
your own delivery location-calculating code, though.

sub filter_recipient ($$$$$$$$$) {
    my ($recipient, $sender, $ip, $hostname, $first, $helo,
        $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_;

    if ($rcpt_mailer eq 'local') {
        my $user = $rcpt_mailer;
	### Note: left out some code where $user is calculated in
        ### another way if spam is already blocked by blacklists
        ### or if another local mailer is used.

        my $uid = getpwnam ($user);
        if ( !defined $uid ) {
            ### Possible an alias, aliasses do not have a uid but are valid...
            ### just accept it.
            return("CONTINUE", "ok");
        }

	### XXX: you'll have to substitute your own mail delivery location
        ### here. We use a NIS map that maps usernames to mailspools.
        tie_nismap(\%mailloc, "mail.deliverylocation")
            or return("CONTINUE", "ok");
        my $maildir = $mailloc{$user};

        # SAMPLE mail location:
        #$maildir = "/var/mail/$user";

        if ( !$maildir ) {
            ### optionally use default location, but that guess
            ### may be wrong, and then mails might inadvertently get
            ### rejected based on the wrong quota.
            return("CONTINUE", "ok");
        }

        ### if $maildir does not exist, take it 1 directory up.
        if ( ! -e $maildir ) {
            $maildir =~ s-/[^/]*$--;
        }

	### XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
	### This is where the actual quota checking starts
        my $dev = Quota::getqcarg ($maildir);
        my ($bc,$bs,$bh,$bt,$fc,$fs,$fh,$ft) = Quota::query($dev, $uid, 0);
        ### if no quota is defined, just accept
        if ( !defined $bh ) {
            return("CONTINUE", "ok");
        }

        ### if usage == limit (or usage > limit!), then no matter how small
        ###  the email, it would never fit. Also, this user has probably
        ###  been over quota for some time, so PERMFAIL it
        if ( $bc >= $bh ) {
            return ("REJECT", "quota exceeded", '552', '5.2.2');
        }

        ### fetch sendmail macros from commands file
	read_commands_file()
	    or return("TEMPFAIL", "Internal error");

        # Assume a mail is 4k unless a ESMTP SIZE= overrides it
        my $mailsize;
        if ( defined $SendmailMacros{msg_size} ) {
            ### round up to next 4k block.
            $mailsize = int(($SendmailMacros{msg_size} + 4095) / 4096) * 4;
        } else {
            $mailsize = 4;
        }

        ### if the email is bigger than what would ever fit in the user's
        ### quota, permfail it
        if ( $mailsize > $bh ) {
            return ("REJECT", "insufficient quota", '552', '5.2.2');
	}

        ### if the mail would exceed the quota, tempfail... this gives
        ### the user a chance to remove some mails and still receive
        ### that large attachment that they were waiting for.
        if ($bc + $mailsize > $bh) {
            return("TEMPFAIL", "quota exceeded", "452", "4.2.2");
        }
    }
    return ("CONTINUE", "ok");
}

-- 
#!perl -wpl # mmfppfmpmmpp mmpffm <pmmppfmfpppppfmmmf at fpffmm4mmmpmfpmf.ppppmf>
$p=3-2*/[^\W\dmpf_]/i;s.[a-z]{$p}.vec($f=join('',$p-1?chr(sub{$_[0]*9+$_[1]*3+
$_[2]}->(map{/p|f/i+/f/i}split//,$&)+97):qw(m p f)[map{((ord$&)%32-1)/$_%3}(9,
3,1)]),5,1)='`'lt$&;$f.eig;                                # Jan-Pieter Cornet



More information about the MIMEDefang mailing list