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 '[EMAIL PROTECTED],[EMAIL PROTECTED],[EMAIL PROTECTED]' 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
_______________________________________________
Visit http://www.mimedefang.org and http://www.canit.ca
MIMEDefang mailing list
[email protected]
http://lists.roaringpenguin.com/mailman/listinfo/mimedefang

Reply via email to