Subject: weird PAM chauthtok behaviour
To: None <tech-userlevel@NetBSD.org>
From: =?ISO-8859-1?Q?Edgar_Fu=DF?= <ef@math.uni-bonn.de>
List: tech-userlevel
Date: 08/25/2007 19:51:38
I just spent most of the day trying to find out why a PAM  
configuration a la (I'm omitting .so, /usr/pkg/lib/security and all  
the options here)

password sufficient pam_ldap
password required   pam_unix

or

password sufficient pam_ldap
password sufficient pam_unix
password required   pam_deny

would work on Linux, but not in NetBSD.

Having found blunder in nss_ldap before, I suspected pam_ldap to be  
the culprit, but not so.

The problem arises from a strange behaviour of OpenPAM's chauthtok  
handling. The whole module chain is run twice, once with  
PAM_PRELIM_CHECK and a second time without. But on that first pass,  
OpenPAM explicitly treats a control flag of sufficient as optional  
(openpam_dispatch.c:137):

  /*
   * For pam_setcred() and pam_chauthtok() with the
   * PAM_PRELIM_CHECK flag, treat "sufficient" as
   * "optional".
   */
  if ((chain->flag == PAM_SUFFICIENT ||
      chain->flag == PAM_BINDING) && !fail &&
      primitive != PAM_SM_SETCRED &&
      !(primitive == PAM_SM_CHAUTHTOK &&
          (flags & PAM_PRELIM_CHECK)))
          break;

So, the only ways I can think of to make password changes work with  
both LDAP and non-LDAP accounts is to either modify pam_deny so it  
will (optionally) not fail for the preliminary phase of chauthtok or  
end the chain with pam_allow. I am however, not sure of the  
implications the latter solution may have on the case of someone  
trying to log in with an expired password. This will force an  
immediate password change, and one might wish to know if it failed or  
not.

Two questions on this:

1. Can someone think on a more elegant way of handling that?

2. Can someone explain to me why OpenPAM handles sufficient as  
optional on the first pass in the first place?