2012. szeptember 11., kedd

OpenLDAP Password Policy on Ubuntu 12.04 - Part Five

Creating the password policy is about to get longer than a Brasilian TV-series. Last time we completed the work with the ppolicy overlay but smbkrb5pwd and Windows will cause headaches.
Today we try to solve the smbkrb5pwd problem. May I remark right here at the beginning that although I solved the problem more or less it was not by design.
Basically it can be done because one can have a policy in Kerberos too. If we specify the same values as in OpenLDAP (in my case: 8 characters long passwords, storing of last three hashes) then we are okay as the Kerberos policy works even when the admin changes the password. (Not like the ppolicy overlay since - as we had the possibility to see it last time - it only works when one chanes her own password.) This way smbkrb5pwd will fail and leaves the other two passwords alone when the new password does not statisfy the policy. This "solution" is okay for me, but if you only use smbkrb5pwd for an LDAP-Samba synch you have to find another solution.

Let us test this method.
We have an overtested user called suser1. She is called suser1 because when we created the Samba server she was the first Samba user. We will use this user again. The kadmin man page states:
-policy policy policy used by this principal. If no policy is supplied,
then if the policy "default" exists and the -clearpolicy
is not also specified, then the policy "default" is used;
otherwise, the principal will have no policy, and a
warning message will be printed.
This means that later we could anyway well use a policy called default. Why not create it now? The following policy is more or less like the one we created in LDAP:
sudo kadmin.local
kadmin.local:  add_policy -minlength 8 -maxlife "3024000 seconds" -failurecountinterval "600 seconds" -lockoutduration "300 seconds" -maxfailure 3 -history 3  default
Let us modify suser1 so she is restricted by this policy:
kadmin.local:  modprinc -policy default suser1
Principal "suser1@ITTHON.CUCC" modified.
If we look at the Kerberos stuff in the LDAP tree we see a leaf called cn=default and this is where the policy resides. Inside the principal of suser1 we find an attribute called krbPwdPolicyReference and that references the default policy.
So now:
ldappasswd -D cn=admin,dc=itthon,dc=cucc -w secret -s thing uid=suser1,ou=People,dc=itthon,dc=cucc
Result: Connect error (-11)
In fact it is not a connect error - see syslog:
smbkrb5pwd conn=1025 op=1 : kadm5_chpass_principal() failed for user suser1@ITTHON.CUCC: Password is too short
So far so good. And now:
ldappasswd -D cn=admin,dc=itthon,dc=cucc -w secret -s 12345678 uid=suser1,ou=People,dc=itthon,dc=cucc
Result: Connect error (-11)
The syslog says:
smbkrb5pwd conn=1026 op=1 : kadm5_chpass_principal() failed for user suser1@ITTHON.CUCC: Cannot reuse password
Cool. As one can see although we granted the right rights for smbkrb5pwd in the context of password changes still it fails because of the policy.
After some testing we realize that the previous Kerberos passwords are not stored and the message we've seen only means that we cannot reuse the present password. But why does the storing not work? The man is always right:
-history number sets the number of past keys kept for a principal. This
option is not supported for LDAP database
Sucks. What now? We change the LDAP default ppolicy so it only stores one password in the history and we set up both places that the password can only change once in an hour. This means to add a  pwdMinAge attribute to the default ppolicy with a value of 3600. The pwdInHistory changes to 1. As for Kerberos the krbMinPwdLife should be 3600. In theory it is okay and we cannot do more.
In practice it is not okay. The smbkrb5pwd does not care about minimal password lifetime. Test it: change the password then use kpasswd to change directly the Kerberos ppassword. It will not work - this way the policy is followed. But if we use once again the command passwd to change the password then update of userPassword will be denied by the ppolicy overlay and smbkrb5pwd happily changes the other two passwords.

It is quiet interesting that the too short password causes the change to fail so that part works. Altogether if using policies we have control over the following:
  • password expiration
  • password minimal length
Quite primitive but that is all we have.

Only one last thing to care about. If you remember if a user has no Kerberos principal then  smbkrb5pwd creates it upon the first password change, Create the user and change her password for example using ldappaswd and keep an eye on the syslog. You will find something like this:
smbkrb5pwd conn=1085 op=1 : created principal for user suser2@ITTHON.CUCC
A quick check:
sudo kadmin.local -q "getprinc suser2"
(a few lines down:)
Policy: [none]
We have two choices:
  1. change the code of smbkrb5pwd or,
  2. write some kind of script that updates all Kerberos principals where nessecary - using eighter kadmin or directly the LDAP.
After a few hours' trying I realized that I am not clever enough to do the first. I am about to understand what to change but that is not enough. So I wrote that script.

First job is to find the principals to modify. As I see we have to chane the ones with no slash in the name and and are of krbPrincipal class and have no krbPwdPolicyReference attribute defined. Translated to ldapsearch:
ldapsearch -x -LLL -b cn=ITTHON.CUCC,cn=krbcontainer,dc=itthon,dc=cucc -s one "(&(!(krbPrincipalname=*/*))(objectClass=krbPrincipal)(!(krbPwdPolicyReference=*)))" dn
Nice looking one, isn't it?
The lovely ldapsearch uses line breaks. The solution is a perl drop (look at the bold):
ldapsearch -x -LLL -b cn=ITTHON.CUCC,cn=krbcontainer,dc=itthon,dc=cucc -s one "(&(!(krbPrincipalname=*/*))(objectClass=krbPrincipal)(!(krbPwdPolicyReference=*)))" dn|perl -p00e 's/\r?\n //g'
We do not need the empty lines:
ldapsearch -x -LLL -b cn=ITTHON.CUCC,cn=krbcontainer,dc=itthon,dc=cucc -s one "(&(!(krbPrincipalname=*/*))(objectClass=krbPrincipal)(!(krbPwdPolicyReference=*)))" dn|perl -p00e 's/\r?\n //g'|grep -v '^$'
We only need the principals:
ldapsearch -x -LLL -b cn=ITTHON.CUCC,cn=krbcontainer,dc=itthon,dc=cucc -s one "(&(!(krbPrincipalname=*/*))(objectClass=krbPrincipal)(!(krbPwdPolicyReference=*)))" dn|perl -p00e 's/\r?\n //g'|grep -v '^$'|cut -d' ' -f2|cut -d',' -f1|cut -d'=' -f2

And the final cut (in plain as my favorite formatter tohtml.com dies formatting it):
for pr in $(ldapsearch -Y EXTERNAL -Q -LLL -b cn=ITTHON.CUCC,cn=krbcontainer,dc=itthon,dc=cucc -s one "(&(!(krbPrincipalname=*/*))(objectClass=krbPrincipal)(!(krbPwdPolicyReference=*)))" dn|perl -p00e 's/\r?\n //g'|grep -v '^$'|cut -d' ' -f2|cut -d',' -f1|cut -d'=' -f2); do kadmin.local -q "modprinc -policy default $pr" 2>&1 >/dev/null; done
This is the one liner to turn into a cron job.
Next time we try to get the Samba policy done.

Further reading:

Nincsenek megjegyzések: