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

Peter Russell pete at enitech.com.au
Wed Feb 22 21:41:27 GMT 2006


Cool thanks the reason i didnt was cos i cant really host the files 
anywhere reliable - solved, i will put itt in before the weekend.
Pete

Glenn Steen wrote:
> 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