Password hardening using PAM
Hi
We have a requirement to validate/enforce password policy by the group to which the user belongs.
The obvious way to do this seems to be to use PAM but I can not find anything that illustrates the syntax required.
In detail we have split users into three groups each one having a specific length and complexity requirement. We have looked into the requirement and come up with what we thought was the correct syntax but we get the standard Authentication token manipulation error.
The syntax we tried was:
password [success=4 default=ignore] pam_succeed_if.so user ingroup wheel
password [success=8 default=ignore] pam_succeed_if.so user ingroup generic
password requisite pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password required pam_deny.so
password requisite pam_cracklib.so try_first_pass retry=3 minlen=16 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass # use_authtok
password required pam_deny.so
password requisite pam_cracklib.so try_first_pass retry=3 minlen=24 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass # use_authtok
password required pam_deny.so
I'm guessing its something quite simple but I have been unable to find it :(
Any suggestions would be greatly appreciated.
Greg
Responses
Remember that PAM is stacked: statement-ordering matters. You'd probably need to have something more like:
password [default=1 success=ignore] pam_succeed_if.so user ingroup wheel
password requisite pam_cracklib.so try_first_pass retry=3 minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
password [default=1 success=ignore] pam_succeed_if.so user ingroup generic
password requisite pam_cracklib.so try_first_pass retry=3 minlen=16 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
In general, you want your pam_succeed and pam_cracklib lines to be ordinally-paired (makes the logic-tracking easier to follow). Using the above should cause the cracklib to apply the minlen=12 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 only if a user's primary group is "wheel" and to apply the minlen=16 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 only if the user's primary group is "generic".
Remember that the success= parameter sets how many rules to skip if the stanza matches. In the modified configuration you're presenting
password [success=4 default=ignore] pam_succeed_if.so user ingroup wheel
if a user is in the "wheel" group, the match-behavior tell s pam, "skip the next four rules" - meaning that the next rule it processes will be:
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
Which probably isn't the behavior you're intending?
Similarly, with your:
password [success=8 default=ignore] pam_succeed_if.so user ingroup generic
Line, if a user is a member of the generic group, PAM skip the over the next eight rules. If there isn't a ninth rule after this stanza, you'll get an error.
Also, because PAM evaluates top to bottom, it operates on a first-match behavior. Thus, if your user is in both the "wheel" and the "generic" group (and your "wheel" rule doesn't cause you to skip straight past the "generic" rule), PAM will attempt to apply both succeed_if skip-actions ...which, if there isn't a ninth rule to evaluate, should result in an error.
The threaded view of this forum isn't the best for reading config-files. It's especially hard to read if you don't use code-tags. Pulling from your immediately-prior response:
password [success=1 default=ignore] requisite pam_cracklib.so try_first_pass retry=3 minlen=16 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
password requisite pam_cracklib.so try_first_pass retry=3 minlen=24 dcredit=-1 ucredit=-1 lcredit=-1 ocredit=-1 maxrepeat=1 type=
In looking at the pam_cracklib man page, I'm not sure that it will honor your [success=1 default=ignore] statement ...which means that, even if you have "SUCCESS", it will continue on to the next match-statement ...resulting all logins still being subject to your default password policy.
Two possible ways around this:
* Pair your pam_succeed/pam_cracklib stanzas (and set your success/default tokens to [default=1 success=ignore])
* Use outer-inner pairings to prevent fall-through (would probably help if I could illustrate this, but this forum doesn't really allow for that)
The former means that your pam_cracklib lines will only get evaluated if the pam_succeed doesn't result in a skip (you may need to invert (negate) your ingroup match-criteria. Down side to this approach is that your users will be subjected to multiple group evaluations rather than single-group evaluations.
Note: been a while since I've tried to implement something like this and I don't currently have access to a test system to verify my statements. Basically going from the frustration-filled, half-decade old memories of what I went through to get things going the way I wanted. Should not that we ultimately ended up throwing it out because the skip-numberins are a very fragile way of enforcing behaviors (if someone came along and modifed your PAM config without being cognizant of module-ordering, all hell would break loose).
FWIW, what we ultimately ended up doing was offloading all (interactive) user management to a centralized directory system. It was a lot easier to apply per-group password (and other security) policies within the context of that directory service than than it was to set up and maintain PAM configs (though, keeping PAM configs in check is also doable via an enterprise CM solution like Puppet or Salt).
Welcome! Check out the Getting Started with Red Hat page for quick tours and guides for common tasks.
