Bug#573596: libnet-ldap-perl: Net::LDAP passes the wrong remote server identity to SASL

Dominic Hargreaves dom at earth.li
Sun Mar 14 17:10:44 UTC 2010


On Fri, Mar 12, 2010 at 11:01:30AM -0800, Russ Allbery wrote:
> The following code in Net::LDAP, introduced in version 0.37 of perl-ldap,
> is unfortunately not correct:
> 
>     # If we're talking to a round-robin, the canonical name of
>     # the host we are talking to might not match the name we
>     # requested
>     my $connected_name = $ldap->{net_ldap_socket}->peerhost;
>     $connected_name ||= $ldap->{net_ldap_host};
> 
> I understand the concern, but this code doesn't accomplish what the author
> intended.  Rather than pass in the canonical hostname of the server to
> which the client actually connected, it's passing in the IP address of the
> remote server.

Ugh. That's my patch. I can only assume that the SASL GSSAPI library 
I was using (MIT I think) does the reverse lookup for itself if it
spots what looks like an IP address (but I won't have time this weekend
to dig into that), because it certainly "works" for us.

> A SASL authentication mechanism that cares about the identity of the remote
> server, such as a Kerberos GSSAPI authentication, will now no longer work
> correctly.  Kerberos, for instance, sees an attempt to authenticate to the
> "hostname" of an IP address, takes off the first octet, and then attempts
> to do cross-realm authentication to a realm named after the remainder of the
> IP address, which of course fails.
> 
> This is not horribly clearly documented, but Authen::SASL in the description
> of client_new() does note that the second argument is a HOST, which in this
> case shouldn't be an IP address.
> 
> There are two possible solutions.  The most correct solution, in my opinion,
> is to simply revert this change and pass in the original host name as given
> to Net::LDAP.  In general, authentication should be done to the original
> host name as specified by the client, not to a canonicalized host name, as
> this provides some protection against DNS spoofing.  The server should
> accept authentications to its canonical advertised LDAP server name, even
> if it's one of a series of round-robin systems.

I found that various other callers (possibly including the OpenLDAP
tools) did do host canonicalisation, so we had to change something
to make things work. My understanding was that although flawed, host
canonicalisation was the standard way of doing things in Kerberos
land.

In general I found it almost impossible to debug these sorts of connection
problems which probably explains why the patch is in the semi-working
state that it's in now - I don't know if I'm missing a trick but even with
turning on all the debugging options I could find you can never get to the
root cause of the authentication failure.

I'll use the sheer frustration that resulted as an excuse for the
nonsensical patch which happened to fix it for us ;)

> If the user really wants
> GSSAPI to canonicalize the hostname, there's generally a way to configure
> the underlying Kerberos library to do that in krb5.conf.

I'll look at that approach too in case it's any good for us.

> However, and I suspect this is what the author ran into, doing this properly
> requires either accepting only the canonical advertised hostname on the
> LDAP server and not, say, the individual server name, or patching Cyrus SASL
> so that it properly accepts multiple authentication identities.  Hence, it
> may be somewhat more reliable to canonicalize before connecting.  In that
> case, what's missing is a reverse DNS lookup of the resulting IP address to
> get back to a hostname.  The code should instead look something like:
> 
>     # If we're talking to a round-robin, the canonical name of
>     # the host we are talking to might not match the name we
>     # requested
>     my $connected_ip = $ldap->{net_ldap_socket}->peeraddr;
>     my $connected_domain = $ldap->{net_ldap_socket}->sockdomain;
>     my $connected_name = gethostbyaddr($connected_ip, $connected_domain);
>     $connected_name ||= $ldap->{net_ldap_host};
> 
> (untested) which I think will also work with IPv6.

Yup, thanks for that. I'll try and look at this issue in more detail
next week with a view to submitting a patch upstream.

Cheers,
Dominic.

-- 
Dominic Hargreaves | http://www.larted.org.uk/~dom/
PGP key 5178E2A5 from the.earth.li (keyserver,web,email)





More information about the pkg-perl-maintainers mailing list