MailScanner, postfix and exchange server as a gateway - try these

Glenn Steen glenn.steen at gmail.com
Wed Feb 22 13:47:23 GMT 2006


Five words for you Pete... Put it in the wiki;-).
You should be able to upload the scripts (image or other file) too.

-- Glenn

On 22/02/06, Pete Russell <pete at enitech.com.au> wrote:
> The postfix method of recipient list is superior to milterahead in that
> it doesnt rely on Exchange being up to function correctly, therefore it
> reduces the functionality of your gateway. IMO
>
> Please find attched the script we plodded from some one else, fixed it
> up and used oursewlves.
>
> 1. It queries AD for ALL of the possible SMTP address for every user in
> the specified domain.
> 2. Check that you havent tried to create an empty file (nothing worse
> than a 0byte recipiuent map)
> 3. Writes the recipient map and runs postmap.
> 4. emails you any error messages so you know what the script is failing.
>
> Simply add the lines to main.cf (we use multiple maps)
>
> relay_recipient_maps = hash:/etc/postfix/1-relay_recipients,
>                           hash:/etc/postfix/2-relay_recipients,
>
> I have the scripts attached to queries Lotus Domino (we use R5) and MS
> AD (we use 2003)
>
> You can see in the script its a sinmple matter to create ANY variation,
> or use regexp to write your maps to cover all the possible valid
> username variations for your company.
>
> Obviously since we made these i have been looking at using regexp, which
> would make easy work of combining heaps of this script into something
> much smaller/smarter.
>
> Hope it helps someone
>
>
> Steve Freegard wrote:
> > On Tue, 2006-02-21 at 11:51 +0000, Martin Hepworth wrote:
> >
> >>For my view, better the devil you know...both are valid, as is exim or
> >>qmail.
> >
> >
> > Indeed - for Exim users - this:
> > http://www.exim.org/mail-archives/exim-users/Week-of-Mon-20040816/msg00126.html might be a good alternative.
> >
> >
> >>For sendmail you'll need to configure milter-ahead, see this..
> >>http://www.fsl.com/support/Milter-Ahead-Exchange-Settings.pdf
> >
> >
> > Note that milter-ahead will only work correctly with Exchange 2003 as
> > it's the only version of Exchange that can be configured to actually
> > *reject* invalid users.
> >
> > Otherwise you have to fall back on the Postfix-style method and create a
> > valid user list.
> >
> > Cheers,
> > Steve.
> >
>
>
> #!/usr/bin/perl -w
>
> # LOTUS DOMINO LDAP DIRECTORY - USERNAMES
> # This script will pull all users' SMTP addresses from your Lotus Domino Directory
> # and list them in the # format "user at example.com OK" which Postfix uses with
> # relay_recipient_maps.
> # Be sure to double-check the path to perl above.
>
> # This requires Net::LDAP to be installed.  To install Net::LDAP, at a shell
> # type "perl -MCPAN -e shell" and then "install Net::LDAP"
>
> use Net::LDAP;
> use Mail::Mailer;
> use Fcntl qw(:DEFAULT :flock);
>
> # Enter the path to your Postfix relay_recipient_maps file
> $RelayRecipientMaps = '/etc/postfix/1-relay_recipients';
> $RecipientMaps = '1-relay_recipients';
> # Script Number
> $sno="Script 1";
>
> # enter the path to the postmap command (or you MTAs equivelent)
> $PostmapPath = "/usr/sbin/postmap";
> # Enter the path to your log
> $HistoryLog = '/etc/postfix/.1-ldap_count';
>
> # Enter the tmp file path
> $RandomValue = rand(9999) * rand(9999);
> $TmpFile = '/etc/postfix/.1-ldap_tmp' . "$$" . ".$RandomValue";
> if (-e $TmpFile) {
>  # Something fishy is going on. Try another file name.
>  $RandomValue = rand(9999999) * rand(9999999);
>  $TmpFile = '/usr/local/etc/postfix/.1-ldap_tmp' . "$$" . ".$RandomValue";
>  if (-e $TmpFile) {
>   &ErrorLog("$sno - Temp file creation failed", "The tmp file $TmpFile already exists after two attempts at different file names. Update aborted.");
>  }
> }
>
> # Enter the maximum variances permitted before the script will fai
> $UCD="50";
>
> # Enter the FQDN of your Lotus Domino Directory below
> $dc1="notes.domain.com";
> $dc2="10.1.10.4";
>
> # Enter the LDAP container for your userbase.
> # The syntax is CN=Users,dc=example,dc=com
> # This can be found by installing the Windows 2000 Support Tools
> # then running ADSI Edit.
> # I use Softerra LDAP Browser to nav the LDAP tree and work out base,
> # username etc.
> # LDAP://domaincontroller1.example.com/CN=Users,DC=example,DC=com
> # which would be $hqbase="cn=Users,dc=example,dc=com"
> $hqbase="o=Domain";
>
> # Enter the username & password for a valid user in your Domino Directory
> # with username in the form cn=username
> # Make sure the user's password does not expire.  Note that this user
> # does not require any special privileges.
> # You can double-check this by typing the Internet Password
> # in the users person doc.
> # LDAP://domaincontroller1.example.com/CN=user,CN=Users,DC=example,DC=com
> # which would be $user="cn=user,cn=Users,dc=example,dc=com"
> $user="cn=Administrator";
> $passwd="password";
>
> # Enter the domain you want to append to your groupnames.
> # we implemented this so we could write maps that included new subdomains etc
> # that didnt appear in person doc info. (Global Domain docs)
>
> $domain1="domain1.com.au";
> $domain2="sub.domain1.com.au";
> $domain3="domain1.edu.au";
>
> # Postmaster email address - send all error messages here.
> $postmaster='prussell at domain1.com.au';
>
> # That's it, you're done.  (Unless you want to play with the LDAP filters below).
>
>
>
>
> # TAB/SPACE you want to use to seperate the
> # email address and the permission eg prussell at domain1.com TAB/SPACE OK
>
> $sep="\t";
>
> # Type of permission, eg REJECT or OK
> $perm="OK";
> # Connecting to Lotus Domino Directory
> $noldapserver=0;
> $ldap = Net::LDAP->new($dc1) or
>    $noldapserver=1;
> if ($noldapserver == 1)  {
>    $ldap = Net::LDAP->new($dc2) or &ErrorLog("$sno - No LDAP Server", "Cannot Access the LDAP server $dc2");
> }
>
> $mesg = $ldap->bind ( dn => $user, password =>$passwd);
>
> if ( $mesg->code()) {
>  &ErrorLog("Bad Password", "The password was invalid. Updated aborted.");
> }
>
> $searchbase = $hqbase;
>
> # Searching for users that are mail-enabled
> $mesg = $ldap->search (base   => $searchbase,
>                        filter => "(|(givenname=*)(sn=*)(shortname=*))",
>                        attrs  => "mail");
>
> $entries = $mesg->count;
>
> if ($entries lt 1) {
> #  die ($errormail);
>         &ErrorLog("$sno - No LDAP queries matched your search", "No data was returned. Updated aborted");
>         #die ("error:", Connection to LDAP successfull. But nothing matched your search criteria"\n");
> }
>
> my $UserCount = 0;
> open(OUT,">$TmpFile");
> flock(OUT, LOCK_EX);
> # Filtering results for name variations.
> foreach my $entry ( $mesg->entries ) {
>    $UserCount++;
>
>    # SHORT NAME VARIATIONS - This will collect ALL shortnames for all users.
>    # prussell@, pruss@, pete@, russell@
>      foreach my $tmp ( $entry->get_value( "shortname" ) ) {
>      print OUT $tmp."\@$domain1$sep$perm\n";
>      print OUT $tmp."\@$domain2$sep$perm\n";
>      print OUT $tmp."\@$domain3$sep$perm\n";
>
>    # First initial.lastname $tmp
>    # p.russell@
>      ($firstchar,$therest) = split(//,$tmp,2);
>      $userwithdot = "$firstchar.$therest";
>      print OUT $userwithdot."\@$domain1$sep$perm\n";
>      print OUT $userwithdot."\@$domain2$sep$perm\n";
>    }
>
>    # FULL NAME
>    # pete.russell@
>      $sn = $entry->get_value( "sn" );
>      $fn = $entry->get_value( "givenname" );
>      print OUT "$fn.$sn\@$domain1$sep$perm\n";
>      print OUT "$fn.$sn\@$domain2$sep$perm\n";
> }
> #close(OUT);
> flock(OUT, LOCK_UN);
> close(OUT);
>
> # Unbinding
> $ldap->unbind;
>
> if (!(-e $HistoryLog)) {
>  # first time run, or someone erased our count file
> # system("/usr/bin/touch","$HistoryLog");
> system("/bin/echo 0 > $HistoryLog");
> }
> open(COUNT,"$HistoryLog") or &ErrorLog("$sno - History Log", "Unable to open $HistoryLog for reading: $!");
> $CountLine = <COUNT>;
> chomp($CountLine);
> if ($CountLine =~ /^(?:\d+)$/) {
>  if ($CountLine - $UserCount > $UCD) {
>   &ErrorLog("$sno -  Results are down by $UCD", "Possible export corruption");
>  }
> } else { &ErrorLog("$sno -  Count file is corrupt", "LastCount file is corrupt"); }
> close(COUNT);
>
> open(COUNT,">$HistoryLog") or &ErrorLog("History Log", "Unable to open $HistoryLog for writing: $!");
> seek(COUNT, 0, 0);
> print COUNT "$UserCount\n";
> close(COUNT);
>
>
> if (-e "$RelayRecipientMaps") {
>  if (-e "$RelayRecipientMaps.backup") {
>   unlink("$RelayRecipientMaps.backup");
>  }
> }
>
> system("/bin/cat $TmpFile > /usr/local/postfix/$RecipientMaps");
> system("/bin/mv","$TmpFile","$RelayRecipientMaps");
> system("$PostmapPath","$RelayRecipientMaps");
> exit;
>
>
> sub ErrorLog {
>  $Subject = "$_[0]";
>  $Message = "$_[1]";
>
>  my $mail = Mail::Mailer->new("sendmail");
>  $mail->open({
>   "From" => "$sno ",
>   "To" => "$postmaster",
>   "Subject" => "$Subject"});
>  print $mail "$Message\n";
>  $mail->close();
>  exit;
> }
>
>
> #!/usr/bin/perl -w
>
> # This script will pull all users' SMTP addresses from your Active Directory
> # (including primary and secondary email addresses) and list them in the
> # format "user at example.com OK" which Postfix uses with relay_recipient_maps.
> # Be sure to double-check the path to perl above.
>
> # This requires Net::LDAP to be installed.  To install Net::LDAP, at a shell
> # type "perl -MCPAN -e shell" and then "install Net::LDAP"
>
> use Net::LDAP;
> use Net::LDAP::Control::Paged;
> use Net::LDAP::Constant ( "LDAP_CONTROL_PAGED" );
>
> # Enter the path/file for the output
> $VALID = "/root/5-relay_recipients";
> open VALID, ">$VALID" or die "CANNOT OPEN $VALID $!";
>
> $RecipientMaps = '5-relay_recipients';
>
> # Enter the FQDN of your Active Directory domain controllers below
> $dc1="10.1.10.8";
> $dc2="10.2.2.32";
>
> # Enter the LDAP container for your userbase.
> # The syntax is CN=Users,dc=mbs,dc=edu
> # This can be found by installing the Windows 2000 Support Tools
> # then running ADSI Edit.
> # In ADSI Edit, expand the "Domain NC [domaincontroller1.example.com]" &
> # you will see, for example, DC=example,DC=com (this is your base).
> # The Users Container will be specified in the right pane as
> # CN=Users depending on your schema (this is your container).
> # You can double-check this by clicking "Properties" of your user
> # folder in ADSI Edit and examining the "Path" value, such as:
> # LDAP://domaincontroller1.example.com/CN=Users,DC=example,DC=com
> # which would be $hqbase="cn=Users,dc=example,dc=com"
> # Note:  You can also use just $hqbase="dc=example,dc=com"
> $hqbase="dc=domain,dc=local";
>
> # Enter the username & password for a valid user in your Active Directory
> # with username in the form cn=username,cn=Users,dc=example,dc=com
> # Make sure the user's password does not expire.  Note that this user
> # does not require any special privileges.
> # You can double-check this by clicking "Properties" of your user in
> # ADSI Edit and examining the "Path" value, such as:
> # LDAP://domaincontroller1.example.com/CN=user,CN=Users,DC=example,DC=com
> # which would be $user="cn=user,cn=Users,dc=example,dc=com"
> # Note: You can also use the UPN login: "user\@example.com"
> $user="CN=grice,OU=Public Accounts,OU=Enterprise,DC=domain,DC=local";
> $passwd="password";
>
> # Connecting to Active Directory domain controllers
> $noldapserver=0;
> $ldap = Net::LDAP->new($dc1) or
>    $noldapserver=1;
> if ($noldapserver == 1)  {
>    $ldap = Net::LDAP->new($dc2) or
>       die "Error connecting to specified domain controllers $@ \n";
> }
>
> $mesg = $ldap->bind ( dn => $user,
>                       password =>$passwd);
> if ( $mesg->code()) {
>     die ("error:", $mesg->code(),"\n");
> }
>
> # How many LDAP query results to grab for each paged round
> # Set to under 1000 for Active Directory
> $page = Net::LDAP::Control::Paged->new( size => 990 );
>
> @args = ( base     => $hqbase,
> # Play around with this to grab objects such as Contacts, Public Folders, etc.
> # A minimal filter for just users with email would be:
> # filter => "(&(sAMAccountName=*)(mail=*))"
>          filter => "(& (mailnickname=*) (| (&(objectCategory=person)
>                     (objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))
>                     (&(objectCategory=person)(objectClass=user)(|(homeMDB=*)
>                     (msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))
>                     (objectCategory=group)(objectCategory=publicFolder) ))",
>           control  => [ $page ],
>           attrs  => "proxyAddresses",
> );
>
> my $cookie;
> while(1) {
>   # Perform search
>   my $mesg = $ldap->search( @args );
>
> # Filtering results for proxyAddresses attributes
>   foreach my $entry ( $mesg->entries ) {
>     my $name = $entry->get_value( "cn" );
>     # LDAP Attributes are multi-valued, so we have to print each one.
>     foreach my $mail ( $entry->get_value( "proxyAddresses" ) ) {
>      # Test if the Line starts with one of the following lines:
>      # proxyAddresses: [smtp|SMTP]:
>      # and also discard this starting string, so that $mail is only the
>      # address without any other characters...
>      if ( $mail =~ s/^(smtp|SMTP)://gs ) {
>        print VALID $mail." \t OK\n";
>      }
>     }
>   }
>
>   # Only continue on LDAP_SUCCESS
>   $mesg->code and last;
>
>   # Get cookie from paged control
>   my($resp)  = $mesg->control( LDAP_CONTROL_PAGED ) or last;
>   $cookie    = $resp->cookie or last;
>
>   # Set cookie in paged control
>   $page->cookie($cookie);
> }
>
> if ($cookie) {
>   # We had an abnormal exit, so let the server know we do not want any more
>   $page->cookie($cookie);
>   $page->size(0);
>   $ldap->search( @args );
>   # Also would be a good idea to die unhappily and inform OP at this point
>      die("LDAP query unsuccessful");
> }
> # Add additional restrictions, users, etc. to the output file below.
> #print VALID "user\@domain1.com OK\n";
> #print VALID "user\@domain2.com 550 User unknown.\n";
> #print VALID "domain3.com 550 User does not exist.\n";
>
> close VALID;
> system("/bin/cat $VALID > /usr/postfix/$RecipientMaps");
> system("/usr/sbin/postmap","$VALID");
>
>
>
> --
> MailScanner mailing list
> mailscanner at lists.mailscanner.info
> http://lists.mailscanner.info/mailman/listinfo/mailscanner
>
> Before posting, read http://wiki.mailscanner.info/posting
>
> Support MailScanner development - buy the book off the website!
>
>
>


--
-- Glenn
email: glenn < dot > steen < at > gmail < dot > com
work: glenn < dot > steen < at > ap1 < dot > se


More information about the MailScanner mailing list