Wandering Thoughts archives


A Linux PAM setup and the problem of stopping authentication

Suppose, not hypothetically, that you have a Linux system where SSH logins are authenticated with passwords and then a MFA challenge. This is implemented the only sensible way, with a PAM module to do MFA, such as the one from Duo; you add this PAM module to your setup along side the existing PAM stuff used for SSH logins. This is all easy to set up and there's plenty of documentation on it, but now you'd like to go the extra distance so that the login fails immediately if people get the password wrong, rather than going on to also do a (pointless) MFA challenge.

(There are good reasons to do passwords first and then stop if that fails.)

In theory this is easy in PAM authentication, using the PAM concept of controls for what the results of PAM modules have. If you set both pam_unix (for passwords) and pam_mfa (for your MFA challenge) to be 'requisite' PAM modules, one after the other, then everything will work right. In practice, the problem is that your Unix is may be doing password checks through a PAM substack. Your /etc/pam.d/sshd may have, for example:

auth required  pam_sepermit.so
auth substack  password-auth
auth include   postlogin

This is from CentOS 7, and all of the password authentication I covered yesterday is in the 'password-auth' substack (in /etc/pam.d/password-auth). Ubuntu has a different setup which we'll cover later.

To simplify the description in pam.conf, a substack essentially becomes a PAM module that is set as 'required'. All of the controls in the substack's configuration (such as 'requisite' or 'sufficient') only affect the evaluation of the substack, and at the end PAM returns control to the surrounding PAM file. On the one hand, this is definitely what we want for a module set up as 'sufficient' in the substack, because when we add pam_mfa to our /etc/pam.d/sshd after the substack, we want it to still challenge people who got the password right. On the other hand, this means that if the substack fails (either by default or through a 'requisite' module failing), we will still go on to do additional things, like our MFA challenge.

In a standard PAM environment, there is no really good way out of this. If we had a hypothetical pam_echostatus PAM module that simply used the current success or failure status of the PAM stack as its own status, we could add it just after the substack as a 'requisite' module; if the substack had returned failure, this would make the failure stop PAM. A more drastic option is to revise the password-auth stack to also check MFA, but only if we're authenticating a SSH session:

auth [success=1 default=ignore]  pam_succeed_if service != sshd
auth requisite   pam_mfa

But this requires additional changes, because we can no longer have pam_unix (or any other module) be 'sufficient', since it isn't. We need a password-auth structure that is more like the Ubuntu one.

Ubuntu 20.04 handles this differently, in a way that explains some of its oddities I mentioned yesterday. The start of /etc/pam.d/sshd on Ubuntu 20.04 is:

@include common-auth

The @include directive is not documented in pam.conf, but we can guess what it does by analogy to the 'include' control that is documented. Since this is an inclusion instead of a substack, a 'requisite' failure in it will abort the entire process and avoid a MFA challenge, even if the MFA challenge is in /etc/pam.d/sshd instead of common-auth. On the other hand, if you accidentally put a 'sufficient' in your /etc/pam.d/common-auth, you've just shot yourself in the foot for any further 'auth' processing in specific PAM service control files like /etc/pam.d/sshd.

(Ie, a 'sufficient' in the Ubuntu common-auth would bypass our additional MFA challenge for SSH logins. Our normal Ubuntu common-auths don't have any 'sufficient' entries, but you might innocently add one for local changes, especially if you're mostly used to the CentOS approach and don't notice or understand the critical difference between a 'substack' and a '@include'.)

linux/PAMStackingAndStopping written at 21:42:43; Add Comment

Page tools: See As Normal.
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.