[Mimedefang] Compliance

Alan Premselaar alien at 12inch.com
Fri Apr 15 03:09:19 EDT 2005


Josh Kelley wrote:
> alan premselaar wrote:
> 
>> I'd be interested in at least looking at it.  Currently I'm using 
>> procmail for local delivery and its Quota handling is kludgey at best.
>> I'd really like to get something working within MD.  Since the method 
>> Jan uses calls the perl module for Quota directly, I don't think 
>> setting setuid on the quota application will make any difference 
>> (although I haven't looked at the Quota module code either)
> 
> 
> Here you go.  A brief explanation:  we're only really interested in 
> checking quotas for students, since faculty/staff don't have quotas.  
> Students use their student IDs for their usernames, with 
> firstname.lastname set up as an email alias, so we have to check 
> aliases.  We test for numeric usernames to see if the account is a 
> student (instead of testing something sensible like the account's gid - 
> I don't know what I was thinking).  Rather than checking current space 
> usage against the message size, as Jan did, we just check to see if the 
> user has already exceeded their soft quota and has exceeded their grace 
> period (i.e., grace is 'none').  This means that the occasional 
> over-the-quota bounce still gets generated (for messages that exceed the 
> hard limit before the grace period expires, or for messages so big that 
> they exceed the hard limit for users currently below the soft limit).  
> This hasn't usually been a problem, but sometime I'll go back and add 
> Jan's enhancements - thanks, Jan, for posting your code.
...snip...

Josh,

thanks.  I took some of your code and Jan's code and hacked it all 
together.  I thought about putting in the alias checking as well except 
that a) I use more than one alias database with sendmail and b) 99% of 
my aliases map to more than one user so it's not likely that 
'user1 at domain,user2 at domain,user3 at domain' is going to map to a UID to do 
quota checking against.  Even if i traversed the list of real users in 
the alias, i'm still in a single recipient stage, so if one real_user in 
the alias is over quota, it would cause the message to be rejected for 
the alias, which I don't really want to do.

the code's only been written against and tested on RHEL ES3.0 linux.

anyways, I figured I'd share my code:

$MAILDIR = "/path/to/mail/directories";
$_QUOTA_CMD = "/path/to/setuid/quota/command";

sub filter_recipient {
	my 
($to,$from,$ip,$name,$first,$helo,$rcpt_mailer,$rcpt_host,$rcpt_addr) = @;
	my $local = ($rcpt_mailer eq 'local');

	my @qrval = &check_quota_info($rcpt_addr) if ($local);

	return(@qrval) if ( $local && lc($qrval[0]) ne 'continue');

	# my greylisting code goes here
	# if this was the only testing done in filter_recipient you
	# could easily just do this:
	#
	# return(&check_quota_info($rcpt_addr)) if ($rcpt_mailer eq 'local');
	#
	# and be done with it.
}

sub check_quota_info {
	my ($to) = @_;

	my $uid = getpwnam($to);

	return('CONTINUE',"ok") if (!$uid);  # possible alias

	my $dev = Quota::getqcarg($MAILDIR);
	my ($bc,$bs,$bh,$bt,$fc,$fs,$fh,$ft) = Quota_query($dev,$uid);

	return('CONTINUE',"ok") if ((!defined $bh) || ($bh == 0));

	## if usage >= limit then perm-fail
	return('REJECT',"Quota exceeded.",'552','5.2.2') if ($bc >= $bh);

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

	my $mailsize;
	if (defined $SendmailMacros{msg_size}) {
		## round up to the next 4k block
		$mailsize = int(($SendmailMacros{msg_size} + 4095) / 4096) + 4;
	} else {
		$mailsize = 4;
	}

	## if the mail is larget than remaining space, tempfail
	return('TEMPFAIL',"Quota exceeded, try again later",'452','4.2.2') if 
($bc + $mailsize > $bh);

	## else accept
	return('CONTINUE',"ok");
}

sub Quota_query {
	my ($device,$uid) = @_;

	my $retval = ();

	my ($mailquota) = grep { /^\s+$device/ } split('\n', `$_QUOTA_CMD $uid`);

	# return if user has no defined quotas
	return(@retval) if ($mailquota =~ /^Disk quotas .{1,30}: none/);

	$mailquota =~ s/^\s+//;

	@retval = split('\s{1,6}',$mailquota);
	shift @retval;		# remove device name from list

	# strip out '*' characters
	foreach my $val (@retval) {
		$val =~ s/\*//g;
	}

	my ($homedir) = (getpwuid($uid))[7];

	# pretend there's no hard limit for user if .forward file exists
	$retval[2] = 0 if (-f "$homedir/.forward");

	return(@retval);
}

I still have the procmail quota kludge setup, so i figure even if some 
stuff sneaks past this code it'll still get a bounce with "mailbox full" 
status, but this should help nearly illiminate unnecessary bounce 
messages. (which i think is a good idea)

thanks again,

alan



More information about the MIMEDefang mailing list