You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@spamassassin.apache.org by "Brian R. Jones" <bj...@castlejones.net> on 2005/04/29 21:05:37 UTC

Need critique on new SA plugin

So I wrote a plugin for spamassassin, and I'd like a few volunteers to 
try/abuse/critique it before I donate it fully to the public domain.

The plugin is ValidLocalUser.pm, and the reason I wrote it is because I 
get a lot of spam to my domain that has the following signature:

Received: ... for valid_user@mydomain.com

To: or Cc: non-existent_user@mydomain.com

Since, counting aliases, I only have a couple of hundred valid users, I 
figured it would be pretty easy to write a plugin to filter on these 
non-existent users.  Well, it wasn't, but that's just because I had 
never written OO perl before.  :)

Anyway, the plugin consists of three pieces:

LocalMailUsers.pm:
	A perl module that supplies a reference to a hash who's keys are all 
the valid email recipients on my mail server.  It is specific to a *nix 
environment.  It seems not unreasonable that a different could be 
written for other environments.

ValidLocalUser.pm:
	This is the plugin.

validlocaluser.cf:
	The config for the pm

To use:
	On my system, I put LocalMailUsers.pm in /usr/local/lib/perl5.  If you 
chose to place it elsewhere, you will need to edit the 'use lib' line in 
ValidLocalUser.pm.
	ValidLocalUser.pm and validlocaluser.cf go in your config directory. 
Since I'm running sitewide, mine is /etc/mail/spamassassin.
	You will need to edit validlocaluser.cf and change 'local_mail_domain 
mycompany.com' to reflect you local domain.


TIA

-- 
Brian R. Jones
Ob.  tagline:
         "I never follow the herd.
                 Even when it's going the right direction."

Re: Need critique on new SA plugin

Posted by "Brian R. Jones" <bj...@castlejones.net>.
Theo Van Dinter wrote:
> On Fri, Apr 29, 2005 at 01:07:23PM -0700, Mike Jackson wrote:
> 
>>find what I'm looking for. It would be nice if, instead of hard-coding 
>>/etc/aliases into the script, you parsed /etc/mail/sendmail.cf and 
>>extracted the value of the "O AliasFile" line. 
> 
> 
> You'd also have to support things that aren't sendmail.  And in sendmail,
> it can just be "OA" as well.  FYI.  ;)
> 
Well, originally I was going to leave the LocalMailUsers.pm as an 
exercise for the student.

I suppose the best way to handle it would be to add more options to the 
conf file that could be passed as args to local_users() to tell it which 
files to read.  but then I'd have to change when local_users was called.

Hmm, I think maybe I will leave it as an exercise to the student.  :)

-- 
Brian R. Jones
Ob.  tagline:
         "I never follow the herd.
                 Even when it's going the right direction."

Re: Need critique on new SA plugin

Posted by Theo Van Dinter <fe...@kluge.net>.
On Fri, Apr 29, 2005 at 01:07:23PM -0700, Mike Jackson wrote:
> find what I'm looking for. It would be nice if, instead of hard-coding 
> /etc/aliases into the script, you parsed /etc/mail/sendmail.cf and 
> extracted the value of the "O AliasFile" line. 

You'd also have to support things that aren't sendmail.  And in sendmail,
it can just be "OA" as well.  FYI.  ;)

-- 
Randomly Generated Tagline:
"Only your father could take a part-time job at a small town paper,
 and wind up the target of international assassins."
         - Marge Simpson, Guess Who's Coming to Criticize Dinner

Re: Need critique on new SA plugin

Posted by Mike Jackson <mj...@barking-dog.net>.
It's a pretty sweet plugin, but since you're asking for feedback, I think 
there's a couple things you could add that would make it more valuable to 
other sys admins:

1. Include /etc/mail/virtusertable as a source of valid users.

2. I don't know how many other admins change this, but I have on my personal 
server. I have Sendmail configured to use multiple aliases files so that can 
segregate system/user aliases, Mailman aliases, and my website staff aliases 
in three separate files. More things to edit, but easier to find what I'm 
looking for. It would be nice if, instead of hard-coding /etc/aliases into 
the script, you parsed /etc/mail/sendmail.cf and extracted the value of the 
"O AliasFile" line. 


Re: Need critique on new SA plugin

Posted by "Brian R. Jones" <bj...@castlejones.net>.
Ken A wrote:
> Hi,
> 
> Nice plugin.
> 
> In localmailusers.pm:
> 
>> current <sourcefiles> are /etc/aliases and /etc/passwd
> 
> What about virtualusertable?

Yeah, should be easy enough to add.

> 
> In validlocaluser.pm:
> 
>> #    Note that the local mail domain can be a perl RegEx,
>> #    i.e. local_mail_domain (:?foo\.com|bar\.org)
> 
> 
> But the more you expand your regex to include more than one domain, the 
> more invalid addresses you actually will accept, right?

Yes, if ken@pacific.net is a valid user, but ken@atlantic.net is not

> 
> Seems like this would be suited to a location with a single domain. 
> Otherwise, it might be better to build a list of valid full email 
> addresses, rather than a list of users with the appended regex for the 
> domain.

I thought about that.  That's for version 2 I guess.  My main priority 
was to get it to work for my own domain.

> 
> The other thing that would get FPs is mail like this list that is sent 
> To: or cc: users@spamassassin.apache.org
> Not sure how you work around that one. Probably would need to lower the 
> scoring a bit, since you'd have a lot of FPs on this one.

Not sure what you mean here, since I'm only looking for invalid users at 
my domain.  The actual contents of To: and Cc: could have any number of 
entries, but if they aren't in the domains I'm interested in, they will 
be ignored.

> 
> Ken A.
> Pacific.Net
> 
> 
> 
> Brian R. Jones wrote:
> 
>> So I wrote a plugin for spamassassin, and I'd like a few volunteers to 
>> try/abuse/critique it before I donate it fully to the public domain.
>>
>> The plugin is ValidLocalUser.pm, and the reason I wrote it is because 
>> I get a lot of spam to my domain that has the following signature:
>>
>> Received: ... for valid_user@mydomain.com
>>
>> To: or Cc: non-existent_user@mydomain.com
>>
>> Since, counting aliases, I only have a couple of hundred valid users, 
>> I figured it would be pretty easy to write a plugin to filter on these 
>> non-existent users.  Well, it wasn't, but that's just because I had 
>> never written OO perl before.  :)
>>
>> Anyway, the plugin consists of three pieces:
>>
>> LocalMailUsers.pm:
>>     A perl module that supplies a reference to a hash who's keys are 
>> all the valid email recipients on my mail server.  It is specific to a 
>> *nix environment.  It seems not unreasonable that a different could be 
>> written for other environments.
>>
>> ValidLocalUser.pm:
>>     This is the plugin.
>>
>> validlocaluser.cf:
>>     The config for the pm
>>
>> To use:
>>     On my system, I put LocalMailUsers.pm in /usr/local/lib/perl5.  If 
>> you chose to place it elsewhere, you will need to edit the 'use lib' 
>> line in ValidLocalUser.pm.
>>     ValidLocalUser.pm and validlocaluser.cf go in your config 
>> directory. Since I'm running sitewide, mine is /etc/mail/spamassassin.
>>     You will need to edit validlocaluser.cf and change 
>> 'local_mail_domain mycompany.com' to reflect you local domain.
>>
>>
>> TIA
>>
>>
>> ------------------------------------------------------------------------
>>
>> #!/usr/bin/perl
>> #
>> #    Package to provide lists of current and former mail users and valid
>> #    mail domains #
>> #    Routines:
>> #
>> #    local_users() returns a reference to a hash containing valid users
>> #        current <sourcefiles> are /etc/aliases and /etc/passwd.
>> #        %{ local_users } =: (
>> #            "user1" => <sourcefile>,
>> #            "user2" => <sourcefile>,
>> #            "user3" => <sourcefile>,
>> #                ...
>> #        );
>> #
>> #    old_users() same as local, but uses site specific practices to 
>> identify
>> #        former users.
>> #
>> #
>> #    Brian R. Jones        04/28/2005
>> #
>> #    Should probably be Mail::LocalMailUsers, but oh well...
>> #
>> package LocalMailUsers;
>> require 5.6.0;
>>
>> use strict;
>> our( @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION );
>> use Carp;
>>
>> BEGIN {
>>      use  Exporter;
>>
>>      @ISA      = qw(Exporter);
>>     @EXPORT    = qw( old_users local_users );
>>     @EXPORT_OK    = ();
>>      %EXPORT_TAGS   = ();
>>      $VERSION  = "0.34";
>> }
>>
>> my $aliasfile    = "/etc/aliases";
>>
>> #
>> #    read the aliases file
>> #
>> sub read_aliases {
>>     my $aliasref    = shift;
>>     my $key;
>>     open(ALIAS, "<$aliasfile") or do {
>>         carp "Can't open aliases file $aliasfile: $!";
>>         return $aliasref;
>>     };
>>     while(<ALIAS>) {
>>         chomp;
>>         /^#/ and next;
>>         /^$/ and next;
>>         /^([\w\.-]+):\s+(\S+)$/ and do {
>>             $key = lc($1);
>>             ${$aliasref}{$key}  = "aliases" unless ${$aliasref}{$key};
>>         };
>>     }
>>     close(ALIAS);
>>     return $aliasref;
>> }
>>
>> #
>> #    Don't use the /etc/passwd, use getpwent instead.
>> #
>> sub pw_users {
>>     my $usersref    = shift;
>>     my ( $user, $pw, $uid );
>>     setpwent;
>>      while ( ( $user, $pw, $uid ) = getpwent ) {
>>           if ( ( $uid == 0 || $uid > 99 ) && ! ( $user =~ m/^gone-/ ) ) {
>>             ${$usersref}{$user}  = "password";
>>           }
>>      }
>>     return $usersref;
>> }
>>
>> #
>> #    former users are still in /etc/passwd, but with "gone-" prepended
>> #    to their username.
>> #
>> sub old_users {
>>     my %users;
>>     my ( $user, $pw, $uid );
>>     setpwent;
>>      while ( ( $user, $pw, $uid ) = getpwent ) {
>>           if ( $user =~ m/^gone-(.*)/ ) {
>>             $users{$1}  = "password";
>>           }
>>      }
>>     return \%users;
>> }
>>
>> sub local_users {
>>     my %users;
>>     pw_users(\%users);
>>     read_aliases(\%users);
>>     return \%users;
>> }
>>
>> 1;
>>
>>
>> ------------------------------------------------------------------------
>>
>> loadplugin ValidLocalUser ValidLocalUser.pm
>>
>> local_mail_domain MyCompany.com
>>
>> header BADLOCALRCPT1 eval:bad_local_rcpt_1()
>> header BADLOCALRCPTFEW eval:bad_local_rcpt_few()
>> header BADLOCALRCPTMANY eval:bad_local_rcpt_many()
>> header OLDLOCALRCPT1 eval:old_local_rcpt_1()
>> header OLDLOCALRCPTFEW eval:old_local_rcpt_few()
>> header OLDLOCALRCPTMANY eval:old_local_rcpt_many()
>>
>> describe BADLOCALRCPT1 invalid recipient @local address
>> describe BADLOCALRCPTFEW 2-3 invalid recipients @local address
>> describe BADLOCALRCPTMANY many invalid recipients @local address
>> describe OLDLOCALRCPT1 no longer valid recipient @local address
>> describe OLDLOCALRCPTFEW 2-3 no longer valid recipients @local address
>> describe OLDLOCALRCPTMANY many no longer valid recipients @local address
>>
>> score BADLOCALRCPT1 1.0
>> score BADLOCALRCPTFEW 1.0
>> score BADLOCALRCPTMANY 2.5
>> score OLDLOCALRCPT1 0.5
>> score OLDLOCALRCPTFEW 1.0
>> score OLDLOCALRCPTMANY 1.0
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> package ValidLocalUser;
>> use strict;
>> use lib '/usr/local/lib/perl5';
>> use Mail::SpamAssassin;
>> use Mail::SpamAssassin::Plugin;
>> use LocalMailUsers qw( old_users local_users );
>> our @ISA = qw(Mail::SpamAssassin::Plugin);
>>
>> sub new {
>>   my ($class, $mailsaobject) = @_;
>>   $class = ref($class) || $class;
>>   my $self = $class->SUPER::new($mailsaobject);
>>   bless ($self, $class);
>>   $self->register_eval_rule ("bad_local_rcpt_1");
>>   $self->register_eval_rule ("bad_local_rcpt_few");
>>   $self->register_eval_rule ("bad_local_rcpt_many");
>>   $self->register_eval_rule ("old_local_rcpt_1");
>>   $self->register_eval_rule ("old_local_rcpt_few");
>>   $self->register_eval_rule ("old_local_rcpt_many");
>>   $self->{"valid_users"}    = local_users();
>>   $self->{"old_users"}    = old_users();
>>   return $self;
>> }
>>
>> #
>> #    Look for the local_mail_domain tag in the config file
>> #    Note that the local mail domain can be a perl RegEx,
>> #    i.e. local_mail_domain (:?foo\.com|bar\.org)
>> #
>> sub parse_config {
>>     my ($self, $opts) = @_;
>>     my $key = $opts->{key};
>>
>>     if ($key eq 'local_mail_domain') {
>>         $self->{main}->{conf}->{local_mail_domain} = $opts->{value};
>>         $self->inhibit_further_callbacks();
>>         return 1;
>>     }
>>     return 0;
>> }
>>
>> #
>> #    Pull the list of local recipients out of the To: and Cc: headers
>> #    bail out with a null list if local_mail_domain isn't defined.
>> #
>> sub _get_local_rcpt_list {
>>     my ( $self, $permsgstatus ) = @_;
>>     my ( $addrs, $maildomain );
>>     my (@addressees);
>>
>>     return \() unless $self->{main}->{conf}->{local_mail_domain};
>>
>>     $maildomain = $self->{main}->{conf}->{local_mail_domain};
>>     $addrs = lc( $permsgstatus->get('ToCc', 0) );
>>     @addressees =   map { m/\b<?(\S+)\@$maildomain>?\b/oi ? $1 : () } 
>> split(/,\s?/, $addrs);
>>     return \@addressees;
>> }
>>
>> #
>> #    count the number of invalid or old local recipients
>> #
>> sub _count_local_rcpts {
>>     my ( $self, $permsgstatus ) = @_;
>>     my $dbg = 0;
>>     for ( @{ $self->_get_local_rcpt_list($permsgstatus) } ) {
>>         if ( $self->{"valid_users"}->{$_} ) {
>>             print STDERR "$_ is a valid local user\n" if $dbg;
>>         } elsif ( $self->{"old_users"}->{$_} ) {
>>             print STDERR "$_ don\'t work here no more.\n" if $dbg;
>>             $permsgstatus->{'old_count'}++;
>>         } else {
>>             print STDERR "$_ ain\'t from around these parts.\n" if $dbg;
>>             $permsgstatus->{'invalid_count'}++;
>>         }
>>     }
>>     return 0;
>> }
>>     
>> #
>> #    Here are the actual tests
>> #
>>     
>> sub bad_local_rcpt_1 {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'invalid_count'};
>>     return $permsgstatus->{'invalid_count'};
>> }
>>
>> sub bad_local_rcpt_few {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'invalid_count'};
>>     if ( $permsgstatus->{'invalid_count'} > 1 ) {
>>         return $permsgstatus->{'invalid_count'};
>>     } else {
>>         return 0;
>>     }
>> }
>>
>> sub bad_local_rcpt_many {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'invalid_count'};
>>     if ( $permsgstatus->{'invalid_count'} > 3 ) {
>>         return $permsgstatus->{'invalid_count'};
>>     } else {
>>         return 0;
>>     }
>> }
>>
>> sub old_local_rcpt_1 {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'old_count'};
>>     return $permsgstatus->{'old_count'};
>> }
>>
>> sub old_local_rcpt_few {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'old_count'};
>>     if ( $permsgstatus->{'old_count'} > 1 ) {
>>         return $permsgstatus->{'old_count'};
>>     } else {
>>         return 0;
>>     }
>> }
>>
>> sub old_local_rcpt_many {
>>     my ( $self, $permsgstatus ) = @_;
>>     $self->_count_local_rcpts($permsgstatus) unless 
>> $permsgstatus->{'old_count'};
>>     if ( $permsgstatus->{'old_count'} > 3 ) {
>>         return $permsgstatus->{'old_count'};
>>     } else {
>>         return 0;
>>     }
>> }
>>
>> 1;
> 
> 


-- 
Brian R. Jones
Ob.  tagline:
         "I never follow the herd.
                 Even when it's going the right direction."

Re: Need critique on new SA plugin

Posted by Ken A <ka...@pacific.net>.
Hi,

Nice plugin.

In localmailusers.pm:
> current <sourcefiles> are /etc/aliases and /etc/passwd
What about virtualusertable?

In validlocaluser.pm:
> #	Note that the local mail domain can be a perl RegEx,
> #	i.e. local_mail_domain (:?foo\.com|bar\.org)

But the more you expand your regex to include more than one domain, the 
more invalid addresses you actually will accept, right?

Seems like this would be suited to a location with a single domain. 
Otherwise, it might be better to build a list of valid full email 
addresses, rather than a list of users with the appended regex for the 
domain.

The other thing that would get FPs is mail like this list that is sent 
To: or cc: users@spamassassin.apache.org
Not sure how you work around that one. Probably would need to lower the 
scoring a bit, since you'd have a lot of FPs on this one.

Ken A.
Pacific.Net



Brian R. Jones wrote:
> So I wrote a plugin for spamassassin, and I'd like a few volunteers to 
> try/abuse/critique it before I donate it fully to the public domain.
> 
> The plugin is ValidLocalUser.pm, and the reason I wrote it is because I 
> get a lot of spam to my domain that has the following signature:
> 
> Received: ... for valid_user@mydomain.com
> 
> To: or Cc: non-existent_user@mydomain.com
> 
> Since, counting aliases, I only have a couple of hundred valid users, I 
> figured it would be pretty easy to write a plugin to filter on these 
> non-existent users.  Well, it wasn't, but that's just because I had 
> never written OO perl before.  :)
> 
> Anyway, the plugin consists of three pieces:
> 
> LocalMailUsers.pm:
>     A perl module that supplies a reference to a hash who's keys are all 
> the valid email recipients on my mail server.  It is specific to a *nix 
> environment.  It seems not unreasonable that a different could be 
> written for other environments.
> 
> ValidLocalUser.pm:
>     This is the plugin.
> 
> validlocaluser.cf:
>     The config for the pm
> 
> To use:
>     On my system, I put LocalMailUsers.pm in /usr/local/lib/perl5.  If 
> you chose to place it elsewhere, you will need to edit the 'use lib' 
> line in ValidLocalUser.pm.
>     ValidLocalUser.pm and validlocaluser.cf go in your config directory. 
> Since I'm running sitewide, mine is /etc/mail/spamassassin.
>     You will need to edit validlocaluser.cf and change 
> 'local_mail_domain mycompany.com' to reflect you local domain.
> 
> 
> TIA
> 
> 
> ------------------------------------------------------------------------
> 
> #!/usr/bin/perl
> #
> #	Package to provide lists of current and former mail users and valid
> #	mail domains 
> #
> #	Routines:
> #
> #	local_users() returns a reference to a hash containing valid users
> #		current <sourcefiles> are /etc/aliases and /etc/passwd.
> #		%{ local_users } =: (
> #			"user1" => <sourcefile>,
> #			"user2" => <sourcefile>,
> #			"user3" => <sourcefile>,
> #				...
> #		);
> #
> #	old_users() same as local, but uses site specific practices to identify
> #		former users.
> #
> #
> #	Brian R. Jones		04/28/2005
> #
> #	Should probably be Mail::LocalMailUsers, but oh well...
> #
> package LocalMailUsers;
> require 5.6.0;
> 
> use strict;
> our( @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION );
> use Carp;
> 
> BEGIN {
>      use  Exporter;
> 
>      @ISA      = qw(Exporter);
> 	@EXPORT	= qw( old_users local_users );
> 	@EXPORT_OK	= ();
>      %EXPORT_TAGS   = ();
>      $VERSION  = "0.34";
> }
> 
> my $aliasfile	= "/etc/aliases";
> 
> #
> #	read the aliases file
> #
> sub read_aliases {
> 	my $aliasref	= shift;
> 	my $key;
> 	open(ALIAS, "<$aliasfile") or do {
> 		carp "Can't open aliases file $aliasfile: $!";
> 		return $aliasref;
> 	};
> 	while(<ALIAS>) {
> 		chomp;
> 		/^#/ and next;
> 		/^$/ and next;
> 		/^([\w\.-]+):\s+(\S+)$/ and do {
> 			$key = lc($1);
> 			${$aliasref}{$key}  = "aliases" unless ${$aliasref}{$key};
> 		};
> 	}
> 	close(ALIAS);
> 	return $aliasref;
> }
> 
> #
> #	Don't use the /etc/passwd, use getpwent instead.
> #
> sub pw_users {
> 	my $usersref	= shift;
> 	my ( $user, $pw, $uid );
> 	setpwent;
>      while ( ( $user, $pw, $uid ) = getpwent ) {
>           if ( ( $uid == 0 || $uid > 99 ) && ! ( $user =~ m/^gone-/ ) ) {
> 			${$usersref}{$user}  = "password";
>           }
>      }
> 	return $usersref;
> }
> 
> #
> #	former users are still in /etc/passwd, but with "gone-" prepended
> #	to their username.
> #
> sub old_users {
> 	my %users;
> 	my ( $user, $pw, $uid );
> 	setpwent;
>      while ( ( $user, $pw, $uid ) = getpwent ) {
>           if ( $user =~ m/^gone-(.*)/ ) {
> 			$users{$1}  = "password";
>           }
>      }
> 	return \%users;
> }
> 
> sub local_users {
> 	my %users;
> 	pw_users(\%users);
> 	read_aliases(\%users);
> 	return \%users;
> }
> 
> 1;
> 
> 
> ------------------------------------------------------------------------
> 
> loadplugin ValidLocalUser ValidLocalUser.pm
> 
> local_mail_domain MyCompany.com
> 
> header BADLOCALRCPT1 eval:bad_local_rcpt_1()
> header BADLOCALRCPTFEW eval:bad_local_rcpt_few()
> header BADLOCALRCPTMANY eval:bad_local_rcpt_many()
> header OLDLOCALRCPT1 eval:old_local_rcpt_1()
> header OLDLOCALRCPTFEW eval:old_local_rcpt_few()
> header OLDLOCALRCPTMANY eval:old_local_rcpt_many()
> 
> describe BADLOCALRCPT1 invalid recipient @local address
> describe BADLOCALRCPTFEW 2-3 invalid recipients @local address
> describe BADLOCALRCPTMANY many invalid recipients @local address
> describe OLDLOCALRCPT1 no longer valid recipient @local address
> describe OLDLOCALRCPTFEW 2-3 no longer valid recipients @local address
> describe OLDLOCALRCPTMANY many no longer valid recipients @local address
> 
> score BADLOCALRCPT1 1.0
> score BADLOCALRCPTFEW 1.0
> score BADLOCALRCPTMANY 2.5
> score OLDLOCALRCPT1 0.5
> score OLDLOCALRCPTFEW 1.0
> score OLDLOCALRCPTMANY 1.0
> 
> 
> 
> ------------------------------------------------------------------------
> 
> package ValidLocalUser;
> use strict;
> use lib '/usr/local/lib/perl5';
> use Mail::SpamAssassin;
> use Mail::SpamAssassin::Plugin;
> use LocalMailUsers qw( old_users local_users );
> our @ISA = qw(Mail::SpamAssassin::Plugin);
> 
> sub new {
>   my ($class, $mailsaobject) = @_;
>   $class = ref($class) || $class;
>   my $self = $class->SUPER::new($mailsaobject);
>   bless ($self, $class);
>   $self->register_eval_rule ("bad_local_rcpt_1");
>   $self->register_eval_rule ("bad_local_rcpt_few");
>   $self->register_eval_rule ("bad_local_rcpt_many");
>   $self->register_eval_rule ("old_local_rcpt_1");
>   $self->register_eval_rule ("old_local_rcpt_few");
>   $self->register_eval_rule ("old_local_rcpt_many");
>   $self->{"valid_users"}	= local_users();
>   $self->{"old_users"}	= old_users();
>   return $self;
> }
> 
> #
> #	Look for the local_mail_domain tag in the config file
> #	Note that the local mail domain can be a perl RegEx,
> #	i.e. local_mail_domain (:?foo\.com|bar\.org)
> #
> sub parse_config {
> 	my ($self, $opts) = @_;
> 	my $key = $opts->{key};
> 
> 	if ($key eq 'local_mail_domain') {
> 		$self->{main}->{conf}->{local_mail_domain} = $opts->{value};
> 		$self->inhibit_further_callbacks();
> 		return 1;
> 	}
> 	return 0;
> }
> 
> #
> #	Pull the list of local recipients out of the To: and Cc: headers
> #	bail out with a null list if local_mail_domain isn't defined.
> #
> sub _get_local_rcpt_list {
> 	my ( $self, $permsgstatus ) = @_;
> 	my ( $addrs, $maildomain );
> 	my (@addressees);
> 
> 	return \() unless $self->{main}->{conf}->{local_mail_domain};
> 
> 	$maildomain = $self->{main}->{conf}->{local_mail_domain};
> 	$addrs = lc( $permsgstatus->get('ToCc', 0) );
> 	@addressees =   map { m/\b<?(\S+)\@$maildomain>?\b/oi ? $1 : () } split(/,\s?/, $addrs);
> 	return \@addressees;
> }
> 
> #
> #	count the number of invalid or old local recipients
> #
> sub _count_local_rcpts {
> 	my ( $self, $permsgstatus ) = @_;
> 	my $dbg = 0;
> 	for ( @{ $self->_get_local_rcpt_list($permsgstatus) } ) {
> 		if ( $self->{"valid_users"}->{$_} ) {
> 			print STDERR "$_ is a valid local user\n" if $dbg;
> 		} elsif ( $self->{"old_users"}->{$_} ) {
> 			print STDERR "$_ don\'t work here no more.\n" if $dbg;
> 			$permsgstatus->{'old_count'}++;
> 		} else {
> 			print STDERR "$_ ain\'t from around these parts.\n" if $dbg;
> 			$permsgstatus->{'invalid_count'}++;
> 		}
> 	}
> 	return 0;
> }
> 	
> #
> #	Here are the actual tests
> #
> 	
> sub bad_local_rcpt_1 {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'invalid_count'};
> 	return $permsgstatus->{'invalid_count'};
> }
> 
> sub bad_local_rcpt_few {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'invalid_count'};
> 	if ( $permsgstatus->{'invalid_count'} > 1 ) {
> 		return $permsgstatus->{'invalid_count'};
> 	} else {
> 		return 0;
> 	}
> }
> 
> sub bad_local_rcpt_many {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'invalid_count'};
> 	if ( $permsgstatus->{'invalid_count'} > 3 ) {
> 		return $permsgstatus->{'invalid_count'};
> 	} else {
> 		return 0;
> 	}
> }
> 
> sub old_local_rcpt_1 {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'old_count'};
> 	return $permsgstatus->{'old_count'};
> }
> 
> sub old_local_rcpt_few {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'old_count'};
> 	if ( $permsgstatus->{'old_count'} > 1 ) {
> 		return $permsgstatus->{'old_count'};
> 	} else {
> 		return 0;
> 	}
> }
> 
> sub old_local_rcpt_many {
> 	my ( $self, $permsgstatus ) = @_;
> 	$self->_count_local_rcpts($permsgstatus) unless $permsgstatus->{'old_count'};
> 	if ( $permsgstatus->{'old_count'} > 3 ) {
> 		return $permsgstatus->{'old_count'};
> 	} else {
> 		return 0;
> 	}
> }
> 
> 1;

Re: Need critique on new SA plugin

Posted by James R <ja...@trusswood.dyndns.org>.
James R wrote:
> Brian R. Jones wrote:
> 
>> So I wrote a plugin for spamassassin, and I'd like a few volunteers to 
>> try/abuse/critique it before I donate it fully to the public domain.
>>
>> The plugin is ValidLocalUser.pm, and the reason I wrote it is because 
>> I get a lot of spam to my domain that has the following signature:
>>
>> Received: ... for valid_user@mydomain.com
>>
>> To: or Cc: non-existent_user@mydomain.com
>>
>> Since, counting aliases, I only have a couple of hundred valid users, 
>> I figured it would be pretty easy to write a plugin to filter on these 
>> non-existent users.  Well, it wasn't, but that's just because I had 
>> never written OO perl before.  :)
> 
> 
> Maybe I'm missing something, but wouldn't it be best to not accept mail 
> to invalid users?
> 
Yes, I am missing something :-D
Ignore, I missed the part about the To:/CC: not matching a real user.

-- 
Thanks,
James

Re: Need critique on new SA plugin

Posted by James R <ja...@trusswood.dyndns.org>.
Brian R. Jones wrote:
> So I wrote a plugin for spamassassin, and I'd like a few volunteers to 
> try/abuse/critique it before I donate it fully to the public domain.
> 
> The plugin is ValidLocalUser.pm, and the reason I wrote it is because I 
> get a lot of spam to my domain that has the following signature:
> 
> Received: ... for valid_user@mydomain.com
> 
> To: or Cc: non-existent_user@mydomain.com
> 
> Since, counting aliases, I only have a couple of hundred valid users, I 
> figured it would be pretty easy to write a plugin to filter on these 
> non-existent users.  Well, it wasn't, but that's just because I had 
> never written OO perl before.  :)

Maybe I'm missing something, but wouldn't it be best to not accept mail 
to invalid users?

-- 

James