#!/usr/bin/perl -w # # See if the mail is addressed to a valid user. # # Do this by examining /srv/$domain/users/{valid invalid}/ # # An invalid user will have two notes set: # # reject -> 1 # reason -> "Mail for $localpart not accepted at $domain" # # # Steve # -- # use Qpsmtpd::Constants; =begin doc This hook is called at "MAIL FROM" time, we record the sender but take no further action. =end doc =cut sub hook_mail { my ( $self, $transaction, $sender, %param ) = @_; # # Record the sender # $transaction->notes( "MAIL-FROM", $sender ); # # But perform no other action. # return (DECLINED); } =begin doc This hook is called at "RCPT TO" time, and will attempt to ensure the recipient is valid. Regardless of whether the recipient is valid we'll return OK to allow the SMTP transaction to proceed. For an invalid user we'll set the "reject" note to 1, and set a suitable reason. =end doc =cut sub hook_rcpt { my ( $self, $transaction, $recipient, %param ) = (@_); # # If a user is a relaying client then all is cool # return (OK) if $self->qp->connection->relay_client(); # # make sure we got a host + user. # return (DECLINED) unless $recipient && $recipient->host && $recipient->user; # # Localpart + domain we're being told to deliver to. # my $host = lc $recipient->host; my $user = lc $recipient->user; # # Record the recipient, and the components. # $transaction->notes( "RCPT-TO", "<$user\@$host>" ); $transaction->notes( "DOMAIN", $host ); $transaction->notes( "LOCALPART", $user ); # # If the domain doesn't have a directory beneath /srv/ then it # is a relay attempt which we must deny. # if ( !-d "/srv/$host" ) { # # Rejected # $transaction->notes( "reject", 1 ); $transaction->notes( "reason", "Relay attempt for \@$host rejected" ); $transaction->notes( "blocker", $self->plugin_name() ); return ( DENY, "Relay attempt for $host" ); } # # Is the local recipient explictly denied? # if ( -e "/srv/$host/users/invalid/$user" ) { # # Explicitly refused. # $transaction->notes( "reject", 1 ); $transaction->notes( "reason", "Mail for $user not accepted at $host" ); $transaction->notes( "blocker", $self->plugin_name() ); return OK; } # # Is mail for this domain enabled on a wildcard basis? # return OK if ( -e "/srv/$host/users/valid/*" ); # # Now we're reaching a conditional point. # # If there is a per-localpart entry for this user then we're # OK, unless it is a directory - in which case we're only OK # if the sending IP sent it. # if ( -e "/srv/$host/users/valid/$user" ) { # # OK the user exists. Is there an ACL in place? # if ( -d "/srv/$host/users/valid/$user/" ) { # # OK ACL in place. Test the sending IP # my $remote = $self->qp->connection->remote_ip; if ( -e "/srv/$host/users/valid/$user/$remote" ) { return OK; } else { $transaction->notes( "reject", 1 ); $transaction->notes( "reason", "Mail for $user not accepted from $remote" ); $transaction->notes( "blocker", $self->plugin_name() ); return OK; } } else { # # Explicitly allowed, with no ACL # return OK; } } # # At this point the mail hasn't been accepted, so it must # be denied. # $transaction->notes( "reject", 1 ); $transaction->notes( "reason", "Mail for $user not accepted at $host" ); $transaction->notes( "blocker", $self->plugin_name() ); # # Return OK, even though we'll drop the mail, because otherwise # we'll get an error from qpsmtpd "No plugin decided whether # relaying was allowed". # return OK; } # # End of module # 1;