Passwordless LDAP authentication
If you're running boxes in an Active Directory or Samba4 Domain, you might get to the point where you need to access the domain's LDAP directory. Hence, you require some kind of authentication.
The classical way involves either using your own domain account, ideally only temporarily; using the Administrator account (which is strongly discouraged, meaning people do it all the time); or creating a dummy user with an even dummier password to use in the application. I admit to having used this way before, but I always felt it to be somewhat ugly, unclean. So finally, I went looking for a better way.
First and foremost, such dummy accounts are maintained by the Domain itself. The machine accounts created when joining a
new box into the domain are exactly that: Accounts used by programs running on a machine to authenticate their access to
Domain resources, like the LDAP directory. So creating yet another dummy account for each application is simply unnecessary.
Machine accounts are named in the format
HOSTNAME$ and put into the Computers subdirectory. They have all the
properties of a standard user, plus a few marking them as computers:
# damien, Computers, local.lan dn: CN=damien,CN=Computers,DC=local,DC=lan objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user objectClass: computer cn: damien whenCreated: 20150201112429.0Z name: damien badPwdCount: 0 badPasswordTime: 0 lastLogoff: 0 lastLogon: 0 sAMAccountName: damien$ objectCategory: CN=Computer,CN=Schema,CN=Configuration,DC=local,DC=lan dNSHostName: damien.local.lan servicePrincipalName: HOST/DAMIEN servicePrincipalName: HOST/damien.local.lan servicePrincipalName: SSH/damien servicePrincipalName: SSH/damien.local.lan distinguishedName: CN=damien,CN=Computers,DC=local,DC=lan
There are more, but you get the idea. So, no need to create yet another user. But what's the account's password?
Getting the password from a machine account is pretty easy if you're on a Linux box. You can use
tdbtool to get the
password from Samba's database, like this:
root@damien:~$ tdbtool /var/lib/samba/private/secrets.tdb tdb> keys key 39 bytes: SECRETS/SALTING_PRINCIPAL/DES/LOCAL.LAN key 38 bytes: SECRETS/MACHINE_PASSWORD.PREV/LOCALLAN key 33 bytes: SECRETS/MACHINE_PASSWORD/LOCALLAN <-- we need this one key 20 bytes: SECRETS/SID/LOCALLAN key 18 bytes: SECRETS/SID/DAMIEN key 41 bytes: SECRETS/MACHINE_LAST_CHANGE_TIME/LOCALLAN key 41 bytes: SECRETS/MACHINE_SEC_CHANNEL_TYPE/LOCALLAN tdb> show SECRETS/MACHINE_PASSWORD/LOCALLAN key 33 bytes SECRETS/MACHINE_PASSWORD/LOCALLAN data 15 bytes  2E ** ** ** ** ** ** ** ** ** ** ** ** 6E 00 .******* *****n
The last line shows the password's bytes encoded in hex and in ascii. Strip the blank in the middle, and you have the plain text password. So now, you have everything needed to connect to the LDAP directory using plain text auth! Behold:
root@damien:~$ ldapsearch -x -H ldap://dc.local.lan -b 'dc=local,dc=lan' -D 'LOCALLAN\DAMIEN$' -w '.************n' '(sAMAccountName=svedrin)' # svedrin, Users, local.lan dn: CN=svedrin,CN=Users,DC=local,DC=lan objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user cn: svedrin whenCreated: 20150201113122.0Z name: svedrin
Getting the Machine account password using Python
In order to retrieve the machine account password, you can also use this little Python script:
Just in case you haven't noticed, now we're really entering the seventh circle of hell. I'm just gonna throw the words Kerberos, SASL and GSSAPI at you. If you're still with me and haven't died of a heart attack, you might even be ready for what's going to be next.
Passwords suck, everyone knows that. So suppose we have joined our box into the domain using a sensible
specifies these options:
kerberos method = dedicated keytab dedicated keytab file = /etc/krb5.keytab
and thereby gives us a keytab to use, we can tell
ldapsearch to authenticate using Kerberos. This eliminates the need
for passwords completely, because the machine already has everything it needs.
However, you will want to make sure,
that the GSSAPI SASL modules are installed. On Debian(ish),
apt-get install libsasl2-modules-gssapi-mitshould do the trick. (If
ldapsearchtries to use
SASL/GSSAPI, the module isn't installed.)
that your DC's name resolution works correctly -- forward and backward. You can check this like so:
root@damien:~$ getent hosts dc.local.lan 2001:6f8:108f:0:5054:ff:febc:c54a dc.local.lan root@damien:~$ getent hosts 2001:6f8:108f:0:5054:ff:febc:c54a 2001:6f8:108f:0:5054:ff:febc:c54a dc.local.lan
So, both entries have to look exactly the same, or else kerberos will fail with some very awkward messages. (Kerberos libraries have a knack for producing less than helpful error messages.)
Now, first of all, we shall authenticate to our domain. To do this, use the
kinit command, telling it to authenticate
using our machine account, getting the password from the keytab file:
root@damien:~$ kinit -k DAMIEN$ root@damien:~$ klist Ticket cache: FILE:/tmp/krb5cc_0 Default principal: DAMIEN$@LOCAL.LAN Valid starting Expires Service principal 14.04.2015 20:27:03 15.04.2015 06:27:03 krbtgt/LOCAL.LAN@LOCAL.LAN renew until 15.04.2015 20:27:03
This looks like a good start: The domain sent us a Ticket-granting Ticket, which basically says "hey, I know you!". Now let's try querying the directory:
root@damien:~$ ldapsearch -H 'ldap://dc.local.lan' -b 'dc=local,dc=lan' '(sAMAccountName=svedrin)' SASL/GSS-SPNEGO authentication started SASL username: DAMIEN$@LOCAL.LAN SASL SSF: 0 ldap_result: Can't contact LDAP server (-1)
Erm. What's this supposed to mean?
Well, this only means that for some reason,
ldapsearch chose to use the wrong authentication mechanism and we need
to give it just a little hint to use
GSSAPI instead of
root@damien:~$ ldapsearch -Y GSSAPI -H 'ldap://dc.local.lan' -b 'dc=local,dc=lan' '(sAMAccountName=svedrin)' SASL/GSSAPI authentication started SASL username: DAMIEN$@LOCAL.LAN SASL SSF: 56 SASL data security layer installed. # svedrin, Users, local.lan dn: CN=svedrin,CN=Users,DC=local,DC=lan objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user cn: svedrin whenCreated: 20150201113122.0Z name: svedrin
Hey, there's our user again! So this time, we accessed the directory without even thinking about passwords.
As I said, we're wandering around circles of hell here. There are no helpful error messages if anything goes wrong,
and there's a lot to go wrong which is not at all obvious. So I'm not sure how much of this stuff you'll actually want
to use. (Maybe someday I'll even figure out how to get
SPNEGO to work, too. So far, no helpful error messages.)