I ran into a problem performing memberOf LDAP queries against an Active Directory controller. Turns out that  while almost everyone is able to read most attributes from user objects, by default memberOf is not visible. The result is that queries using memberOf do not return a result. I was frustrated that the queries worked when tested on a domain controller using the LDP.exe utility, when tested as a domain admin. I was focused on getting the LDAP query correct and had not stopped to consider that the LDAP bind account I was using could not read the memberOf attribute.

Anyway, turns out that “Read Member Of” is a property you can assign via the Active Directory Users and Computers MMC. Right click on the top OU from where you want the permission to be granted (this might be the root of the AD tree or a sub-OU) and select “Properties”. Select the “Security” tab and then click “Advanced”. You can now add a permission for the LDAP bind user (or group as needed) using the “Add” button. Select a principal (i.e. user / group as needed), choose “Allow” for the “Type” and then you’ll probably want “Applies to” to be “This object and all descendant objects”. Scroll the bottom of the screen and choose “Clear all” and then find and select the property “Read Member Of”. Save and close the windows and your LDAP bind account should be able to filter based on group membership.

The below is a simple Perl snippet (based on code from http://search.cpan.org/dist/perl-ldap-0.55/lib/Net/LDAP/Examples.pod) to test the LDAP queries.

use Net::LDAP;

$ldap = Net::LDAP->new ( "dc01.example.com" ) or die "$@";
#if you has LDAPS enabled you can use the following instead
#$ldap = Net::LDAP->new ( "ldaps://dc01.example.com" ) or die "$@";
$mesg = $ldap->bind ( "CN=ldapbind,OU=Services,DC=ad,DC=example,DC=com",
 password => "LongSecretPassword",
 version => 3 );

#@Attrs = (); # to request all attributes
 my @Attrs = ( 'cn','mail','givenName','sn','sAMAccountName');
 my $base = "DC=ad,DC=example,DC=com";
 #find members of the group
 #my $filter = "(memberOf=CN=Some-group,OU=Groups,DC=ad,DC=example,DC=com)";
 #find all objects with a sn attribute
 #my $filter = "sn=*";
 #find active users within the specified group
 my $filter = "(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(memberOf=CN=Other-group,OU=Groups,DC=ad,DC=example,DC=com))";
 #my $result = LDAPsearch ( $ldap, $query, \@Attrs );
 my $result = $ldap->search ( base => "$base",
 scope => "sub",
 filter => "$filter",
 attrs => \@Attrs
 );

my @entries = $result->entries;
 my $entr;

foreach $entr ( @entries ) {
 print "DN: ", $entr->dn, "\n";

my $attr;
 foreach $attr ( sort $entr->attributes ) {
 # skip binary we can't handle
 next if ( $attr =~ /;binary$/ );
 print " $attr : ", $entr->get_value ( $attr ) ,"\n";
 }
 print "#-------------------------------\n";
 }

A useful summary of LDAP search options supported by AD servers (incl for disabled accounts and nested-group membership) is in an article titled “Active Directory: LDAP Syntax Filters“.

Well I am trying to upgrade MailScanner on one of my servers. Alas, these upgrades are never straight forward. The MailScanner upgrade went reasonably smoothly but when it came to starting MailScanner the problem showed itself. Starting MailScanner resulted in the following error:

root@host:/opt/MailScanner/bin# ./MailScanner
 is only avaliable with the XS version at /usr/local/share/perl/5.8.7/Compress/Zlib.pm line 9
BEGIN failed--compilation aborted at /usr/local/share/perl/5.8.7/Compress/Zlib.pm line 9.
Compilation failed in require at /opt/MailScanner/lib/MailScanner/SA.pm line 42.
BEGIN failed--compilation aborted at /opt/MailScanner/lib/MailScanner/SA.pm line 42.
Compilation failed in require at ./MailScanner.orig line 110.
BEGIN failed--compilation aborted at ./MailScanner.orig line 110.
root@host:/opt/MailScanner/bin#

The root of the error is the message about “is only avaliable with the XS version” within Compress/Zlib.pm line 9. There are a few posts relating to this but no real resolutions. One of the common suggestions, which works for a few people it seems, is to force reinstall the Scalar::Util Perl module. Use “force install Scalar::Util” from within the CPAN shell. This didn’t work for me.

I tried a short test script to try reproduce the problem:

use Scalar::Util qw(dualvar);
use Compress::Zlib;
print "$Scalar::Util::VERSIONn";
my $foo = dualvar 10, "Hello";
print "$foon";

This worked which indicates that the XS functionality is working properly.

I figured it might be related to the load order of the libraries. For MailScanner 4.79.11-1 I managed to work around this problem by inserting

use Scalar::Util qw(dualvar);

in at line 38 (just after “require 5.005;”). This appears to load the Scalar::Util XS functions before MailScanner alters the library search paths.

Hopefully this helps someone else with this problem.