Two OpenLDAP TLS gotchas

The scenario:

  • You’re using CentOS 7 or RHEL 7.
  • You’re using OpenLDAP.
  • You have TLS set up on OpenLDAP.
  • You are trying to perform a query against the server using ldapsearch.

Problem #1:

You get:

ldap_start_tls: Can't contact LDAP server (-1)
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)

Possible solution:

You’re using the -Z option (along with -h and -p) to specify the host and port and request TLS. That option doesn’t work.

Instead, just use the -H option and specify the parameters as an LDAPS URL.

For example:

ldapsearch -x -Z -h localhost -p 636 -b 'dc=example' '(objectClass=*)'

becomes:

ldapsearch -x -H ldaps://localhost:636/ -b 'dc=example' '(objectClass=*)'

This is actually mentioned on the OpenLDAP FAQ if you look hard enough:

Most clients now have a -Z flag which enables sending the StartTLS extended operation to the server. This extended operation initiates TLS negotiation. To use ldaps://, one must use -H ldaps://.

(Emphasis mine.) I’ve no idea what -Z is for, given that it isn’t needed if you use -H with an LDAPS URL, and doesn’t work if you don’t.


Problem 2:

Having worked out how to request a TLS connection, it still doesn’t work, so you try adding the -d 1 argument to turn on some debugging. In the client’s debug logs you see either:

TLS: error: tlsm_PR_Recv returned 0 - error 21:Is a directory

or

TLS: error: tlsm_PR_Recv returned 0 - error 13:Permission denied

Solution:

You probably have SELinux enabled. OpenLDAP doesn’t work with SELinux. Disable it and reboot the server, or work out how to persuade SELinux to let openldap open its own config files.

My first Rust disappointment

Rust is an up-and-coming new programming language which offers compile time safety, automatic memory management, and C-like performance.

It also offers automatic resource management. In Java terms, it takes AutoCloseable, formalizes it more, and makes it ubiquitous throughout the language. When a resource is accessed, it is given a scope of applicability; when the scope ends, the resource is automatically closed. This eliminates problems like unclosed file and database handles.

To make this work throughout the language without annoyance, Rust introduces the ability when calling into another scope to either pass ownership of a value or lend it. If the value’s ownership is passed, the old scope can no longer access it, and the new scope owns it. If the value is borrowed, the called code can no longer access the borrowed value after returning.

With that background, here’s my first disappointment with the language, given that it seems to be trying to do everything right this time.

Yehuda Katz writes:

In practice, the reason this works so well is that most of the time, functions that take values are “borrowing” them. They take a value, do some work with the value, and return. Holding on to the value for longer, for example by using threads, is both uncommon and an appropriate time to think a little bit about what’s happening.

The starting point when writing new functions is to borrow parameters, not try to take ownership. After a little while of programming with Rust, this imposes no cognitive cost; it’s simply the default.

Except it’s not. The syntax for taking ownership is:

fn is_thirties(person: Person) {  
  person.age >= 30 && person.age < 40
}

For borrowing, it’s:

fn is_thirties(person: &Person) {  
  person.age >= 30 && person.age < 40
}

This leads me to propose a rule for future language designers:

When designing syntax for a programming language, the safest and most desirable behavior should be the one with the least syntax.

Rust has apparently repeated the mistake Java made with final parameters: it has made the unadorned syntax be the one you shouldn’t do unless you have a really good reason.

I appreciate that Rust’s choice is probably to make the syntax look familiar to C++ programmers, but to me that seems like a really bad tradeoff. The vast majority of programmers aren’t C++ programmers, and I daresay the majority of C++ programmers aren’t capable of using it safely, so optimizing for them is pessimizing for most use of the language.

Sure, it’s only a single character in front of every parameter, rather than the word final, but to me that makes it worse — it’s really easy to miss a single character.

What I think should have been done would have been for Rust to lend parameters by default; taking ownership of a parameter would then require an explicit warning notation, like an ! on the front. But then, that wouldn’t have looked like C. And of course, it’s far too late to change it now.

Yes, this is a very minor issue. It’s just that I’m old enough and cranky enough these days that when I read about a new programming language, I generally only get through a few pages before hitting an “oh my god what were they thinking” moment. (Go error handling. Scala’s arrow fetish and occasionally needing semicolons. Haskell’s responses to trivial errors. CoffeeScript semantic indentation. Perl 6 operators.) Rust is unusual in that I read entire articles and still wanted to try it, which is why the undesirable default behavior of function arguments disappoints me.