#!/usr/bin/perl -w use CDB_File; use warnings; use strict; # locallist.pl - build local.cdb file for distribution # Copyright (C) 2006, ed neville # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # purpose: # to combine every email address that our systems receive email for # into a single cdb file which can be distributed amoung the mail # cluster. the main goal is to avoid accepting *@smtproutes, # which could be bounced. so, place the validrcptto from all other # cluster nodes in $validsmptroutes files which are read and negate # the smtproutes state in %rcpttohosts etc # # in this file we totally ignore the smptroutes, those have nothing # of use until we merge all the files together later, unless # locallistsmtproutes exists in the control directory # # thanks: # thanks to nathan (owner of link9.net) for help # # based on the work by JMS (http://qmail.jms1.net). # # maintained by ed@ NOSPM usenix.org.uk # # current version 0.2 # # changelog # # 20060102 ewn very alpha code # 20060104 ewn added support for smtp routes # globals my $qd = "/var/qmail"; my $aliases = "/etc/aliases.cdb"; my %localdomains; # default domain/locals my %locallist; # localusers for @above^ # path to files for reading in as valid addresses my $validsmptroutes = "/var/qmail/validsmtproutes"; my $vpopmailbin = "/home/vpopmail/bin"; my $name; my $live = 0; # here are the actual recipients # user@domain, or @domain # a SMTP route is classed as @domain my %list; sub dop( $ ) { if( not $live ) { my $val = shift; print( $val . "\n" ); } } sub getname { open( F, "/etc/hostname" ) or die( "Cannot open /etc/hostname" ); while( my $line= ) { chomp( $line ); next if( $line =~ /#.*/ || length( $line ) == 0 ); $name = $line; } close( F ); } sub isfastforward( $ ) { my $filename = shift; my $retval = 0; open( FF, "$filename" ) or die( "Cannot open: $filename" ); while( my $line = ) { if( $line =~ /^(\s*)\|(\s*)fastforward.*$/ ) { $retval = 1; } } close( FF ); return( $retval ); } sub dosmtproutes { if( not -f "$qd/control/locallistsmtproutes" ) { return; } my $pathname = "$qd/control/smtproutes"; if( not -f $pathname ) { return; } open( F, $pathname ) or die( "Cannot open $pathname" ); while( my $line = ) { chomp( $line ); $line =~ /^([^#].*):.*$/; $list{"\@$1"} = 1; } close( F ); } sub isdeliverbounce( $ ) { my $filename = shift; my $retval = 0; open( FF, "$filename" ) or die( "Cannot open: $filename" ); while( my $line = ) { if( $line =~ /vdelivermail.*bounce\-no\-mailbox/ ) { $retval = 1; } } close( FF ); return( $retval ); } sub defaultdomain { # unsure if here if mail from psybb@mail.link9.net should be # accepted. my @arr = qw( defaultdomain locals ); foreach my $file ( @arr ) { my $path = "$qd/control/$file"; open( DD, $path ) or die( "I cannot open $path" ); while( my $line =
) { chomp( $line ); next if( $line =~ /\#/ ); $localdomains{$line} = 1; } close( DD ); } # deal with .qmail files, including -default my $path = "$qd/alias"; opendir( AD, "$path" ) or return; while( my $line = readdir( AD ) ) { next if( $line eq "." || $line eq ".." ); $line =~ s/^\.qmail-//; $line =~ s/:/./g; $line =~ s/^default$//; chomp( $line ); if( $line eq "" ) { if( isfastforward( "$qd/alias/.qmail-default" ) == 0 ) { $locallist{$line} = 1; } else { next; } } $locallist{$line} = 1; } closedir( AD ); } sub localusers { my $path = "/etc/passwd"; if( -f "/etc/passwd" ) { open( P, $path ) or die ( "Could not open: $path" ); while( my $line =

) { my @row = split( /:/, $line ); if( defined( $row[0] ) && $row[0] ne "" && length( $row[6] ) > 1 ) { $locallist{$row[0]} = 1; } } close( P ); } } sub virtuals { my %h; tie ( %h, 'CDB_File', '/var/qmail/users/cdb' ) # or die "Untied!\n"; or return; while ( ( my $k, my $j ) = each %h ) { my @uc = split( /\0/, $j ); if( not defined( $uc[3] ) ) { next; } $k =~ /^!(.+)\-$/; $k = $1; # run /home/vpopmail/bin/vuserinfo -n -D is-cool.net # go through mail boxes my $cmd = "$vpopmailbin/vuserinfo -n -D " . $k . "|"; open( VU, $cmd ) or return( "Could not execute: $cmd" ); while( my $line = ) { chomp $line; if( $line =~ /^.+$/ ) { $list{"$line\@$k"} = 1; } } close( VU ); # go through valiases $cmd = "$vpopmailbin/valias -s $k |"; open( VU, $cmd ) or return( "Cannot execute: $cmd" ); while( my $line = ) { chomp $line; next unless ( $line =~ /^(.+?)\@/ ); $line = $1; $list{"$line\@$k"} = 1; } close( VU ); # go through any remaining .qmail- files my $path = $uc[3]; opendir( DD, $path ) or die( "Cannot open $uc[3]" ); while( my $fl = readdir( DD ) ) { if( $fl =~ /^\.qmail-(.+)$/ ) { my $us = $1; my $pathname = "$uc[3]/$fl"; next if ( isdeliverbounce( "$path/.qmail-default" ) == 1 ); $us =~ s/^default$//; $us =~ s/\:/./g; $list{"$us\@$k"} = 1; } } closedir( DD ); } untie( %h ); } sub fastforwards( $ ) { my $path = shift; if( -f $path ) { tie( my %ff, 'CDB_File', $path ) or die( "Cannot tie to $path" ); while( ( my $forward, my $deliver ) = each ( %ff ) ) { $forward =~ /^:(.*)\@(.*)$/; my $dom = $2; my $email = $1; if( $dom eq "" ) { # this is a local $locallist{$email} = 1; } else { $list{"$email\@$dom"} = 1; } } untie( %ff ); } } sub printlist { my $path = "$validsmptroutes/$name.cdb"; my $c = CDB_File->new( $path, "$path.tmp" ); while( ( my $dom, my $val ) = each( %localdomains ) ) { while( ( my $email, my $val ) = each( %locallist ) ) { dop( "$email\@$dom" ); $c->insert( "$email\@$dom", "\0" ); } } while( ( my $email, my $val ) = each( %list ) ) { dop( "$email" ); $c->insert( "$email", "\0" ); } $c->finish; } getname; defaultdomain; localusers; virtuals; fastforwards( $aliases ); dosmtproutes; printlist;