Archives / Search ›

And now for something completely different…

More broken software.

I can’t get my RSS feed to rerender; it’s still stuck thinking it’s reStructuredText when it is HTML. Maybe, just once, PyDS would get it right and I wouldn’t have to rerender parts of my site every time I make a weblog post. I’m posting this as much to complain as to see if another post will cause the RSS to be regenerated.

For all its failings, Radio got this one right pretty much all the time. How I wish I had time to fix this…

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.

‹ Newer Posts