Archives / Search ›

Kerberized LDAP from a scripting language, part 2

Patrick Boettcher helped me figure out my problems using Authen::SASL::Cyrus with Net::LDAP.

Authen::SASL supports plugins for different SASL implementations: Authen::SASL::Perl includes pure-Perl methods, and Authen::SASL::Cyrus which talks to Cyrus SASL or SASL2. When it fails to find one of these modules, it gives the “No SASL mechanism found” message. But, in my case, the modules were installed and readable.

I was once again caught by my umask. I had installed a bunch of other modules from the CPAN shell, as root with an 077 umask, and the Perl module searching mechanism, I assume, gave up once it couldn’t access a file or directory, even though none of the inaccessible modules were dependencies of Authen::SASL::Cyrus. The Authen::SASL::Cyrus module, which I compiled manually, was installed and readable.

Finally, I needed to use SASL2; compiling Authen::SASL::Cyrus with SASL1 gave me a Perl equivalent of the useless “Local error” I was seeing in Python. python-ldap had been using SASL2 all along.

Here’s the script I ended up with:

#!/usr/bin/env perl

# Generate aliases from Active Directory users with 'mail' attributes.

use strict;
use warnings;
use diagnostics;

use Net::LDAP;
use Authen::SASL;
use Expect;

\$Expect::Log_Stdout = 0;

my \$timeout = 5;
my \$expect = Expect->spawn('/usr/kerberos/bin/kinit',
    or die "can't spawn kinit: \$!\n";
\$expect->expect(\$timeout, 'Password for postfix@MED.UIUC.EDU:');

# empty callback so Net::LDAP doesn't override it
my \$sasl = Authen::SASL->new('GSSAPI', 'user' => '');
my \$ldap = Net::LDAP->new('',
                          version => 3) || die "\$@";

my \$mesg = \$ldap->bind('', sasl => \$sasl);
\$mesg->code && die \$mesg->error;

\$mesg = \$ldap->search(base => 'dc=med,dc=uiuc,dc=edu',
                      filter => '(&(mail=*)(objectClass=user))',
                      attrs => ['mail', 'userPrincipalName']);
\$mesg->code && die \$mesg->error;

open(ALIASES, '>> /home/lists/aliases');
foreach my \$entry (\$mesg->sorted('userPrincipalName')) {
    my (\$username) = 
        (\$entry->get_value('userPrincipalName') =~ /([^\@]+)\;
    unless (\$username) {
        die "can't understand principal name\n";
    print ALIASES \$username . ': ' . \$entry->get_value('mail') . "\n";



I got the basic idea of the above from Chris Covington’s Postfix & Exchange 2000/2003 how to.

No comments yet. Be the first.

Leave a reply