Kerberized LDAP from a scripting language?

Any scripting language? Any scripting language at all?

My goal: to set up an virtual map in Postfix, mapping usernames to email addresses where present, using a LDAP server (Windows 2000 Active Directory) as a data source, in a reasonably secure fashion. Using OpenLDAP 2.0.27, Cyrus SASL 2.1.15, ldapsearch on the command line did exactly what I wanted, so I thought it’d be simple enough to script. Was I ever wrong!

  • Attempt 1, /etc/postfix/main.cf:
     virtual_mailbox_maps = ldap:medicine medicine_server_host = med-banting.med.uiuc.edu medicine_query_filter = userPrincipalName=%s@med.uiuc.edu medicine_search_base = dc=med,dc=uiuc,dc=edu medicine_result_attribute = mail [...] 

    What to do for the […]? Can’t use a simple bind: too insecure. The AD server is not configured to support SSL. Postfix doesn’t support GSSAPI. That leaves anonymous binding, which I couldn’t, after many hours with ADSI Edit, get to do what I wanted. Even if I accepted the security problem of allowing people to enumerate all the users at our site, I couldn’t get anything beyond a DN for domain administrators, some of whom require the above email mapping. It does not seem possible to limit access via IP address.

    So, I resigned myself to running a cron job to populate a hash map or similar with periodic dumps of the LDAP information.

  • Attempt 2, python-ldap 2.0.0, search.py:
     #!/usr/bin/env python2.3 import ldap, ldap.sasl server = ldap.initialize("ldap://med-banting.med.uiuc.edu") server.sasl_interactive_bind_s("", ldap.sasl.gssapi("")) res = ldap.search_s("dc=med,dc=uiuc,dc=edu", ldap.SCOPE_BASE,           "(&(mail=*)(objectClass=user))") print res server.unbind() 

    In competition for the least helpful error message of the century, up there with “An error has occurred: Success”:

     % ./search.py Traceback (most recent call last): File "./search.py", line 8, in ?   server.sasl_interactive_bind_s("", ldap.sasl.gssapi(""))  File "/usr/lib/python2.3/site-packages/ldap/ldapobject.py", line 196, in sasl_interactive_bind_s   return self._ldap_call(self._l.sasl_interactive_bind_s,who,auth,serverctrls,clientctrls)  File "/usr/lib/python2.3/site-packages/ldap/ldapobject.py", line 94, in _ldap_call   result = func(*args,**kwargs) ldap.LOCAL_ERROR: {'desc': 'Local error'} 

    I am not the only person with this problem.

  • Attempt 3, Net::LDAP (part of perl-ldap 0.31), Authen::SASL::Cyrus 0.11, search.pl:
     #!/usr/bin/perl use Net::LDAP; use Authen::SASL; my $sasl = Authen::SASL->new('GSSAPI', 'user' => ''); my $ldap = Net::LDAP->new('med-brevis.med.uiuc.edu', version => 3) || die "$@"; my $mesg = $ldap->bind("", sasl => $sasl); $mesg->code && die $mesg->error; $mesg = $ldap->search(filter => '(&(mail=*)(objectClass=user))',            base => 'dc=med,dc=uiuc,dc=edu',            attrs => ['mail', 'userPrincipalName']); $mesg->code && die $mesg->error; @entries = $mesg->entries; foreach $entry (@entries) {   $entry->dump; } $ldap->unbind; 

    This looks so good, as just a month ago, people claimed it worked. It doesn’t for me.

     % ./search.pl No SASL mechanism found at /usr/lib/perl5/site_perl/5.8.0/Authen/SASL.pm line 62 

After over eight hours of work on this, and assuming I don’t hear back from anyone by tomorrow, attempt #4 is going to be parsing the output of ldapsearch. I was going to get research work done today, too…

Posting code from PyDS’s RPC interface is a complete nightmare; it unescapes everything constantly, tries to interpret $-macros, etc… I guess Georg just uses reStructuredText, but that’s no use until I have a weblog editor that supports it.

No comments yet. Be the first.

Leave a reply