Many interactive commands are security sensitive.
An obvious example is
passwd used to change a user's
Such commands require users to authenticate themselves even though
they have successfully logged in to the system.
Also many server daemons carry out tasks on behalf of remote
users, and most of these require the daemon to authenticate
the remote user.
Early versions of Unix had all such programs (applications and daemons)
directly read and parse the
/etc/passwd file, so they
could authenticate users.
This became a problem when the format of
changed to include aging information in the second field.
Every program that needed to authenticate users had to be updated
Sometime after that, single (remote) user databases became common
in large organizations, using technology such as
This meant a second set of such commands (all NIS
commands start with the letters “yp”, as in
Soon shadow passwords became common, then Kerberos,
then different password encryption (actually, hashing)
algorithms (such as MD5), then LDAP, etc.
Every such change either requires custom versions of applications
and daemons, or a re-write of the existing versions.
And for every program that needed authentication!
At some point, someone came up with the idea that programs that need authentication should use a standard library for that, which in turn could be configured to use different databases and/or new algorithms just by adding new DLLs (called shared object files in Linux or Unix). This system became known as PAM (Pluggable Authentication Modules). Using PAM, some new authentication DLL can be invoked by the PAM library just by editing a text configuration file (which says which authentication modules to use). “PAM-ified” programs do not need to be changed in any way to use different authentication modules. Only a text configuration file (one for each program) needs to be updated to change how some program authenticates users.
From the FreeBSD PAM documentation: PAM was defined and developed in 1995 by Vipin Samar and Charlie Lai of Sun Microsystems, and has not changed much since. In 1997, the Open Group published the X/Open Single Sign-on (XSSO) preliminary specification, which standardized the PAM API and added extensions for single (or rather integrated) sign-on. PAM is widely used by BSD (OpenPAM), by Linux (PAM-Linux) and by Solaris (Solaris PAM).
To see if some program is “PAM-ified” or not, check if it has been compiled with the PAM library:
ldd cmd | grep libpam.so
Modern (and most legacy) applications and daemons that need authentication have been re-written (hopefully for the last time!) to use PAM. There are many PAM modules (yes I know that's redundant but saying “PAMs” or “PA modules” is awkward) available for every system, each supporting a different authentication method. New ones can be easily found on the Internet, or created by programmers. A nice benefit of this design is that different programs can use different PAM modules for authentication, all on the same system. (Each program's text configuration file may specify a different set of PAM modules to use.)
In addition to authentication, PAM modules can be used for
session setup and tear-down, logging, and various other uses.
For example, there is a PAM module to display the
Another module changes the owner, group, and permissions of various
/dev, to allow users logged in at the
console permission to use sound or access removable media.
The PAM configuration file for some program can list more than one
PAM module to try, and each is tried in the order listed.
So if the user fails to authenticate using the PAM module for (say)
local files (
then PAM will try the next module listed, which can attempt
authentication using a different database such as NIS,
LDAP, or even Windows AD.
PAM modules don't only allow or deny access by authenticating users. They can check other things to determine access. For instance, some PAM modules deny access if the resource is busy with too many users already. Others can allow or deny users based on criteria such as the time of day.
Because of PAM's utility and flexibility, system administrators should become familiar with the system and the set of PAM modules available to them. Then they can implement a wide range of security policies for the various applications and services on their hosts.
PAM is not the only such framework available, but it is the most widely used. Others on Linux include GSAPI and SSSD. Note that most of these frameworks include PAM modules, so even if some application uses one of them, they can still be configured through PAM. Also, PAM usually includes modules to use these other frameworks, leading to the possibility of the application using PAM to use (say) GSAPI, which may be configured to use PAM. Some care is needed to avoid this. (See overlapping below for more details.)
Keep in mind that PAM, like all such frameworks, can only inform the programs that use it whether or not a user should be allowed access. PAM cannot enforce that; a badly written program, or one infected with malware, might still perform its function even if a user is not authenticated or authorized. Other security subsystems, such as SE Linux, can enforce policy.
In the PAM configuration file for some program (application or daemon), the administrator lists all the PAM modules that should be used to implement the access policy. This list is called a stack. When a program needs to authenticate a user, each PAM module is invoked in the order listed in the configuration file for that program. Each module can return success or failure. The results of all the modules are combined into a single result. This process is controlled by the “control-flag” listed for each module. Generally, if any one module “fails”, then PAM informs the application that access is denied.
The exact behavior of PAM in the event that one module fails can be changed in the configuration file, allowing for complex policies to be implemented. For example you can configure some program to try to authenticate with LDAP first, and if that fails try local files. Then allow access if either module succeeds.
Take for example an application such as
This is written to use PAM to see who is allowed to run that
The exact set of modules is controlled by a text configuration
(or policy) file in the
the configuration file is called
(It is common but not required to use the application's name as
the configuration file's name.)
By editing this configuration file, you can enforce any access
Here's the default
hwbrowser PAM configuration file
from a Fedora Core Linux system:
/etc/pam.d# cat hwbrowser #%PAM-1.0 auth sufficient pam_rootok.so auth sufficient pam_timestamp.so auth required pam_stack.so service=system-auth session required pam_permit.so session optional pam_xauth.so account required pam_permit.so
As you can see, the file has a list of DLLs to use, and some of them are passed extra arguments. (The syntax of PAM configuration files is discussed below.)
If an application can't find a configuration file for itself, it
defaults to using the
other PAM configuration
It is important for security reasons to have an
other” configuration file!
Typically this file should deny all access.
This is a deny by default policy.
The administrator will need to create (if missing) a PAM
configuration file for any “PAM-ified” program to be used
on the system.
By editing (or creating if missing) these files, a system administer implements access policy for the applications and servers on the host. Don't forget that other security systems may also require configuration to implement a host's access policies, including firewalls, TCP Wrappers, file permissions and ACLs, group memberships, SE Linux policy files, service configuration files, SASL, and so on.
SASL is a framework for authentication mechanism negotiation. A server can advertise one or more authentication mechanisms to clients, and the two can agree on which one to use. (Most mail servers use this.) It is not uncommon to have SASL configured to allow the use of PAM. See Cyrus SASL for System Administrators and RFC-4422 for more information on SASL.
PAM modules are usually stored in the
/lib/security or the
Do an “
ls” of this directory to see what PAM modules
have been installed on your system.
Additional modules may be put anywhere, but if so the configuration
file needs to list the complete pathname of the module.
Each PAM module is really just a DLL that defines one
or more of the six standard functions that PAM will use.
These functions are grouped into four types, or
contexts (I believe the official term is management group):
Any given PAM module will implement the functions needed for
one or more of these types.
(So, a module that only implements
will do nothing if used in any other context.)
To see which functions a given PAM module implements, your first
thought should be to consult the documentation.
When that is lacking, you can run the command:
nm --dynamic --defined-only pam_module.so
to see which PAM functions are defined in that module. An “auth” module will define the function
pam_sm_authenticate(), an “account”
module will define
pam_sm_acct_mgmt(), a “session”
module will define both
a “password” module will define
Any PAM module must define at least one set of these functions, and
may define several.
A program written to use the PAM library calls a series of functions that in turn invoke the functioned defined in various PAM modules. A typical application makes the following function calls to the PAM library:
... pam_start(...); Initializes the PAM library ... if ( ! pam_authenticate(...) ) Authenticates using "auth" modules error_exit(); ... if ( ! pam-acct_mgmt(...) ) Checks for a valid, unexpired account and verifies access restrictions with "account" modules error_exit(); ... pam_setcred(...) Sets extra credentials, e.g. a Kerberos ticket ... pam_open_session(...); Sets up the session with "session" modules do_stuff(); pam_close_session(...); Tear-down session using the "session" modules pam_end(...);
The only part of this a system administrator needs to understand is that a program that uses PAM will make function calls to the PAM library, and these in turn invoke functions in the related PAM modules.
pam_start function is passed a service name
as the first argument.
This name is nearly always the same as the program's name.
The PAM configuration files in
/etc/pam.d are named
by this service name.
So if the application or server daemon has a different filename, an
administrator won't know which PAM configuration file it uses!
If the service name isn't obvious and you can't find it in the
program's documentation (or don't trust that) you can determine
this name yourself, by checking the string passed as the first
argument to the
If you don't have access to the source code you can use tracing
and debugging tools to determine the service name.
Here's an example on Linux to determine the service name of the
$ ltrace /usr/bin/vlock 2>&1 1>/dev/null </dev/null |grep 'pam_start' pam_start(0x8049ac0, 0x804a4c0, 0x804a210, 0xbf82adcc, 0x4554005a) = 0 ^^^^^^^--> this is the RAM address of the service name $ gdb /usr/bin/vlock (gdb) printf "%s\n",0x8049ac0 vlock (gdb) quit
This method won't work if the binary has been stripped (or is
not readable by the current user).
A better method is to use a tracing tool, such as
strace on Linux,
to see which files the command opens:
# strace -uwpollock -e open -o strace.out chfn # grep /etc/pam.d strace.out # Hint: not "other" or "system-auth". # rm strace.out
So a PAM program starts.
The correct configuration file is found and read.
The program then calls
which in turn calls a specific function
pam_sm_authenticate()) in each of the
“auth” modules listed in the configuration file,
The results are combined according to the control-flags
for those modules.
pam_authenticate() returns a result
back to the program.
The other PAM functions used by the program work the same
If some “auth” module wants to ask the user to re-enter a password, the module invokes a function in the application to prompt the user and to get the input. This is called a “call-back” function.
This is documented in the
pam.conf man page on your system.
Older versions of PAM used one large
with each line starting with the name of the service the line
In modern PAM, each service has its own file in
The syntax is the same except that first field is omitted, even
though the man page may still mention it.
If both the
/etc/pam.conf file and the
directory exist, Linux PAM will ignore the file.
Each line contains a module context (or type), the
control flag, the module, and
module options (if any).
Blank lines and comment lines (starting with “
are also allowed.
(Some implementations of PAM allow for long lines to be continued, using
the convention of ending a line with a backslash.
Don't rely on this unless you are certain your implementation
The context says when the module is used:
for authentication, for password updates, or for session
The control flag tells PAM how to react to the module's
result (e.g., pass or fail).
For determining authorization to run a command, only the lines that
start with “
auth” and “
The others (“
password”) can be ignored.
(They have other uses, such as initializing the environment, logging command's
use, or approving a new password.)
auth modules determine who the user is and if that user has
a valid account on this machine (authentication).
account modules determine if the user is allowed
Some possible “account” policies you can test for include: the
account and password are not expired, must be a system account, only a certain
number of users may run this command (say FTP) at once,
access only allowed during certain hours, access from the console only
(i.e. not a remote user), and others.
The relevant modules are run in order listed in the file. Most software checks authentication (“auth”) modules first. Once the user is authenticated, the authorization (“account”) modules are then run. If all is well, “session” modules may be run next, if any. If the software allows a user to update their credentials (passwords), any “password” modules are then run. When the task is finished, the software will run the “session” modules again, to close the session.
Some PAM modules that logically should be in the session setup are run as “auth” modules. The reason is that some environment settings have security implications, or affect the user interface (when asking for a password for example), and need to run first.
Modules are passed information about the request and user, plus any module options listed on the end of the line. Each module returns a result such as pass or fail. The modules are run until an overall decision is reached, which is either pass or fail. (In more sophisticated configurations, many different return values can occur, and the configuration file can say what to do for each.) The final result is passed back to the application.
A description of most standard PAM modules can be found in the
PAM Administrator's Guide, but often the name alone suggests what
a module does.
Not every module is listed in this one guide.
However many PAM modules have
man pages (and
many don't), so if not listed in the guide try
(I.e. to find info on
pam_console.so module try
If this doesn't work you must look on the Internet for information.
A good place to start is
The Linux-PAM web site.
Failing that you can always try a Google search.
For example, a search for “
man page for pam_timestamp.
Enough with the theory!
Examine the first line from the
auth sufficient pam_rootok.so
A description of this “
pam_rootok” module can be
found in the on-line
PAM Administrator's Guide, but the name alone suggests what it
If the user is
root, then that is sufficient to allow
access to this command.
sufficient” control-flag means that if the
module passes, that is if the user is root, no further
(auth) modules need to be tried.
But if the user is not
must try the other auth modules listed (if any) to decide whether
to allow access.
The next “
auth” line is:
auth sufficient pam_timestamp.so
What does this mean?
Looking up this module in the guide we find... nothing!
In this case the man page is locally installed and we find this
“... In a nutshell,
pam_timestamp caches successful
authentication attempts, and allows you to use a recent successful
attempt as the basis for authentication. ...”
This means that if you have successfully authenticated recently
say by supplying your password,
that will be remembered for several minutes and you can use the
command without authenticating yourself again.
(This module was invented for the use of the
The timestamp is the modification time on a file, by default
You can also determine for how long after that time your
credentials remain valid; default is 5 minutes.)
Now look at the last
auth required pam_stack.so service=system-auth
required” control-flag means that if the
module is used, it must pass or the overall result will be
fail, regardless of the status of other modules.
pam_stack module runs all the modules in
the file listed after
service= (another PAM config file),
and returns whatever result that file's modules return.
Modern Linux PAM no longer uses
Instead two new keywords are available for use in the configuration
include and the similar
(They differ in their handling of the sub-module's sufficient success
(“done”) and requisite failure (“die”);
see the pam.conf man page for details).
On a modern system, the above line would look like this:
auth include system-auth
pam_stack.so line says that the user can use the
hwbrowser command if they pass all the
modules listed in the PAM configuration file
This is a Red Hat thing.
The folks at Red Hat decided to centralize a lot of security
policies into that one file.
(Other systems use the same idea, but a different file name.)
If you look at some other configuration files in
/etc/pam.d on a Red Hat based system,
you will see the same line.
system-auth file is over-written each
time the “
authconfig” command is run, so
it is important to keep a backup copy of this file handy
if you edit it manually.)
Centralizing your default access policy in one PAM configuration file
is a good idea, so if and when it changes you need only update that
Now look at the last line:
account required pam_permit.so
A quick check of this module says it merely always returns pass. This is here because if there is no module for some type, PAM may return fail if an application tries to invoke it. You can ignore such lines as they have no effect on PAM's overall result.
Putting these lines together we get this policy: A user can run the
hwbrowser command: if the user ID is zero
root), or if the user recently authenticated, or
(if neither of those) if the user passes the common policy
system-auth file is discussed below.)
If none of those pass, access is denied and the attempt is logged.
Suppose the policy on your site changes so root and only root should
be allowed to use the command
To implement this new policy, an administrator need only comment
out the second and third “auth” lines in the configuration file.
As mentioned above, the “
control-flag means that if the module passes, that is
enough and the remaining modules in the same context
auth”) are ignored.
On the other hand, if the module fails, that doesn't mean an overall
result of fail.
If a subsequent
sufficient passes, or if all subsequent
required modules pass, then the overall result is
(You can think of
sufficient as if no failures so far,
stop checking and return success.)
required” control-flag means it isn't enough to
pass this one module to be allowed to run the command.
required modules tried must
say “pass” before access is granted by PAM.
required module fails, the remaining
required modules are still tried
so that hackers won't know exactly which one failed, but it won't
matter if any of them pass.
(Note that a
sufficient modules that passes will
prevent any following
required modules from running, as
PAM will have stopped at that point.)
requisite” control-flag means the same as
required flag, except when the module fails.
required, the overall result is fail.
The difference is that with
no further modules are tried.
(It is a fail-fast version of
optional” control-flag means that the success
or failure of that module has no effect.
Generally, this flag is used for session modules only.
A missing module acts like a “fail”, and the error is logged (via
the system logging daemon, usually
If a line in the configuration file starts with a dash, the error isn't logged. This can be useful for modules that may not be present, for example, a module for fingerprint authentication may not be present, but if it is, it should be used.
To prevent authentication failure when a module is missing,
such modules should be used with
sufficient rather than
required, such as:
-auth sufficient pam_fingerprintd.so
The order of the modules is significant.
If a prior
required module fails, and
sufficient module passes, access
will be denied.
auth required pam_moduleA auth sufficient pam_moduleB auth required pam_moduleC
What policy does this implement? It says access is allowed: if both modules A and B pass, or if both modules A and C pass. On the other hand, the policy implemented with:
auth sufficient pam_moduleB auth required pam_moduleA auth required pam_moduleC
says to allow access: if module B passes, or if modules A and C both pass.
But, what does pass mean exactly?
Each PAM module examines information provided by the program
requesting authentication (usually the user's ID
and a supplied password), plus other information found
elsewhere (often there are per-module configuration files found
PAM then decides if the current user passes the authentication test
and meets the required account policies.
If so the module returns “pass”; otherwise it returns “fail”.
Actually PAM modules can return several different status values
and not simply pass or fail.
The control flag can say to do this if the
status is one thing, and to do that if the status is
In practice the older scheme of just pass and fail, with the
control-flag keywords of
required, is flexible enough for most policies,
and is commonly used.
You might occasionally see other control-flags listed in some
pam” man page and
PAM Administrator's Guide
describe everything that can go there in gory detail.
But for most policies, you only need to understand the
It is not specified what happens when the PAM config file for some
application is empty, or all of the (say) AUTH modules have been
commented out, or listed as
By reading the
source for Linux PAM
pam_dispatch.c) and running some experiments,
I have determined that Linux PAM does the safe action: it fails in
But system administrators should not rely on this undocumented
Always have some
sufficient) module for each type, even if only
In short, all modules of the correct type (context) are tried in the order
listed, except when a
sufficient module passes, or a
requisite module fails.
In those two cases, the remaining modules are not run and PAM returns a
Back to our story!
Recall the PAM configuration file for
also requires the common policy in
(remember you can ignore the rest)
/etc/pam.d/system-auth file look like this
(the default file on an old Fedora Linux system):
auth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth required pam_deny.so account required pam_unix.so account sufficient pam_localuser.so account sufficient pam_succeed_if.so uid < 500 quiet account required pam_permit.so
Each of these modules should be looked up in the PAM reference
That would tell you what each is for and what the
module arguments such as “
Basically this (system default) policy authorizes a user to run
some command if the user provides a valid password.
(You've probably have seen this behavior when you try
any command with a similar access policy (
passwd are some examples);
root you don't get asked a password to run
hwbrowser, but as a regular user you must supply
a password to run it.)
As mentioned previously, this is the same as
that if the module fails no further modules are tried.
In other words
requisite is a “fail fast”
auth section says access is permitted if
the user supplies a valid password.
If they don't, fail quietly if this is a system account, otherwise,
pam_deny fails with a log message.
modules are interesting because they are used in two different
The explanation is that modules have different set of functions that
get invoked depending from which context they are called.
pam_unix.so module for example:
auth context this
module checks the user's name and password,
but in the
account context this same module checks
the account's aging and expiration information instead.
Many modules have multiple purposes, depending on the context.
When reading the documentation for some module, be sure
to refer to the part that describes the purpose of the module,
for the context in which that the module is used.
pam_unix.so does not currently check
if a user's account is locked!
It logically should do so in the
account context, but apparently
the assumption is that a locked account won't pass the
context, since locking accounts on Unix and Linux is done by altering the
However, if a user uses biometrics or SSH keys to authenticate,
the mangled password hash is never examined!
And what if you don't use the shadow suite, but something like LDAP instead? Then you just use a different module. This is the power of PAM: an easy way to change which authentication methods are used without re-writing all your applications, or changing the configuration of each application separately.
pam_unix.so module (and similar modules on other
systems such as the Solaris 8
use standard system calls to check users and passwords.
On modern systems these system calls can use different account
databases depending on settings in the
So, to use (say) NIS you either use the
pam_nis.so module (if one is available on your
system), or use
pam_unix.so and configure the
nsswitch.conf entries for
group to use
A recently developed module uses SSSD, a common
service for all remote authentication, which can cache credentials
for when the network is unavailable.
All these modules are nice, but the overlap in functionality means there are many, slightly different ways to use the same authentication service (single sign-on). To use LDAP for example, you could:
The bottom line is that there is more than one way to configure a given access policy! However, there can be subtle differences in the various modules.
account section is interesting.
The first line says the user must have a valid (unexpired)
The second says it is sufficient if that user is listed in the
while the third line says it is sufficient if you are a system
account (that is, an account with a UID of less than 500).
But the second through fourth
account lines don't
seem to do anything!
You can comment out those three lines and the result is apparently
the same policy.
(What policy do you think they were trying to implement
The explanation may be that (as mentioned above)
pam_unix uses the standard
system calls to check for users and passwords, and those system
calls may not be checking any local files.
So the intended policy is probably to allow a user
if it is a standard system account, or
if it is a valid account in the local
/etc/shadow files, or if it is a valid account
in the standard (usually networked) database.
(What changes would you make to correctly implement this
Solaris 10 and newer no longer support
These have been replaced with a bunch of better modules.
See the Solaris
pam.conf(4) man page for more information.)
While you could restrict the use of
root by changing the permissions on the program
(or change group membership or by adding ACLs),
this is not a good way to do control access.
Such changes get lost when updating commands, are hard to remember,
and do not log violations.
So you should use PAM to enforce your policies whenever possible.
Suppose you decide to change the
so that only
root is allowed to run the command.
Take another look at the
hwbrowser configuration file's
auth sufficient pam_rootok.so auth sufficient pam_timestamp.so auth required pam_stack.so service=system-auth
What would happen if you changed “
required” in the
root access would be required.
However PAM would still try
and run through the modules listed in
If those lines were commented out as well as changing
sufficient” to “
in the first line, then you get the behavior you want:
root can run the command.
requisite would work too.
(To comment out a module means adding a “
in the front of the line listing that module.)
(Note that just commenting out the second and third
lines will work too; if there are no
the failure of all the
sufficient modules will cause PAM to`
But this is undocumented PAM behavior, so I suggest you change
required as well as
commenting out the second and third lines.)
Other PAM changes are simpler.
To modify “
su” to use the
group membership for sufficient or required permission to run
a command, examine the
To change the minimum required password length, look at the
/etc/pam.d/passwd file, only in that case you will
only see references to the
So go look at that file again.
If you want a different policy for some command, don't use
include in that command's PAM configuration file.
Many system administrators mistakenly think they can set minimum
password length in other configuration files such as
But changes to those files may or may not have any effect!
It depends on your version of Unix or Linux used, as well as the
version of the
passwd command on your system
and which database you are using (e.g., shadow suite,
You should always set the password policy using PAM. If you do set a minimum length in some other file(s) and those settings are used on your system, then a candidate password must meet the criteria from both the file(s) and from PAM. So you might as well only set your policy with PAM.
When changing passwords (or other user credentials),
modules are used to determine password policies
such as which database of passwords to use (e.g.,
/etc/shadow, RADIUS, LDAP, etc.) and
password constraints (e.g., minimal length, types of characters
required such as a mix of letters and digits, etc.).
auth” modules are still used to make sure the
current user has permission to change the password, but it is
password modules that determine acceptable passwords.
If you look up the
password modules found in
in the on-line PAM reference, you will quickly discover
that only the “
pam_cracklib” module controls password
constraints such as minimum password length, at least on Linux.
(Newer distros of Linux use the newer but compatible
pam_pwquality” module instead.)
This is done in a complex way so you really need to read
that module's description and the provided examples carefully.
(See some notes regarding pam_cracklib and pam_pwquality
Not all systems provide the exact same PAM modules, but usually
there are similar ones to the PAM-Linux distribution.
If your system doesn't seem to have
see if there is another module with similar functionality.
On Solaris for example, you can use
You need to be careful! Modules with the same name may work differently on different systems. Always check the documentation and verify your PAM configuration files implement the policies you think they do. A good way to do that is to run experiments to test your policies.
The default policies (the ones controlled by PAM anyway) aren't always the most secure, and you should carefully review them on any upgraded system as part of the post-install process. A larger organization can have standardized PAM configurations that can be applied as a patch or RPM (or similar) package.
pam_unix module in a PAM configuration
file with the context (module type) of “account” checks
that an account exists and isn't expired.
It does not check if an account has
been locked or has an invalid shell!
pam_unix assumes the
component will fail if the account is locked.)
This means that users using SSH keys to log in
will be allowed to do, so even if you lock their accounts with
passwd -l” command (since
sshd doesn't use the PAM auth modules in this
Setting an invalid shell is checked with the Linux
pam_shells module, but that is usually included
only in the configuration files for FTP
(I've been locking users out this way for years and I've
never realized the danger.
Now I always add
pam_shells in the
part of my PAM configuration (as
and lock accounts by specifying an invalid shell such as
sshd, and other remote access services.)
Solaris 10 and newer no longer use
It has been replaced it with other modules that each do part of what
pam_unix used to do.
pam_unix_account module does check
for locked accounts.
Some versions of
sshd do check for locked accounts,
but only when configured to not use PAM.
When configured to use PAM, and
sshd uses keys
to authenticate the user,
sshd apparently only uses
session modules and
While Linux PAM doesn't contain any(!)
that can check for locked accounts, you may be able to find one you
can use from non-standard PAM modules found on the Internet, or
create one yourself.
(Note that not all *nix systems have this security bug.)
The best way to prevent account access is to expire the account. That is checked by default in all PAM stacks. Access can be restored by setting a new expiration date (in the future).
As mentioned previously PAM modules are not limited to returning only pass or fail. Linux PAM defines over 30 different return values that a module might return (listed below). Instead of one of the original control flags (required, sufficient, requisite, and optional) you can use the new syntax with square braces, like this:
type [value=action value=action ...] module options
You can list any one of seven different actions for each possible
That's a lot of flexibility!
value is one of the following
PAM module return values:
action says how to combine this return
value for the module in the overall pass or fail
value that is returned to the application for the whole
It is one of:
ok” value will not be used to override that value. (This is essentially the same as the old “required” flag when the module returns SUCCESS, and is indeed often used as “
okwith the side effect of terminating the module stack and PAM immediately returning to the application. (Similar to “sufficient”.)
Each of the four control-flag keywords (required, requisite,
sufficient, and optional) have an equivalent expression in terms
[success=ok new_authtok_reqd=ok ignore=ignore default=bad]
[success=ok new_authtok_reqd=ok ignore=ignore default=die]
[success=done new_authtok_reqd=done default=ignore]
[success=ok new_authtok_reqd=ok default=ignore]
As an example from an old Fedora system, consider the
lines from the
smartcard-auth PAM file:
auth required pam_env.so auth [success=done ignore=ignore default=die] pam_pkcs11.so nodebug wait_for_card auth required pam_deny.so
pwquality PAM modules
are very similar;
pwquality is a modern replacement
For both, the documentation uses the term minimum length or
minlen”, but it's really a “score” of
complexity, and not just the length of a password.
A password is acceptable if it passes certain checks (for example, not based
on a dictionary word or your account name), and has a complexity
score equal to or greater than
This score for a candidate password is computed as follows when
using the default settings (cracklib and older pwquality):
pam_cracklib and older
the default values for
The defaults for modern
pam_pwquality are different:
0 (zero) for all credits and
minlen defaults to
(These defaults are almost certainly no longer sufficient to prevent password
cracking by brute-force, so consider increasing
The DoD/DISA recommendation (2015) is stricter:
minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1
which requires at least one each of a digit, an uppercase letter, a lowercase letter, and a symbol. (This recommendation changes over time. You can find some recommendations in DoD Changes to UCR 2008, section 126.96.36.199.1.2, part 1b subsection 8, (PDF), I think from 2015; DoD STIG for Red Hat Enterprise Linux 7; or from “Passwords do not meet complexity or strength.” STIG teleconference (2014).
If the score is less than the value for
the password is not acceptable (it “fails” the module's
Here's an example to illustrate how the complexity is calculated:
minlen=8 is used with
If the user tries to set a password of “
then cracklib/pwquality will not allow it.
The score for this password is 6 + 1 = 7 (assuming
lcredit=1) but the minimum allowed score is 8.
The score for “
Foobar” would be
6 + 1 + 1 = 8, and that would
“pass” this test.
The score for “
aB1$” would be
4 + 1 + 1 + 1 + 1 = 8.
You don't have to use such a complex test if you don't want to.
If you set the credit for each type of character to zero then only
the length of the password will matter.
(This is in fact the default with
Besides this strength/complexity test for a minimum “length”,
has a hardcoded minimum number of bytes
(characters) in the password of 4.
(Perhaps because the U.S. government specifies that as a minimum
In addition the system password changing code often defines a
minimum length (number of characters, not minimum strength), whether
or not you use
For Solaris, a length is defined in
For Linux (when using the “shadow” suite) it is defined
/etc/login.defs and possibly other files
Setting the credit for (say) digits to a number greater than
one or to a negative value allows more complex passwords to
Say you set
Then you will add zero to the score if no digits
are in the candidate password, add one if there is one digit, two
if there is two digits, and three if there is three or more
Basically the value is a maximum amount of extra credit you can
have by using that type of character in your passwords.
Setting the four credit values to 0 (zero) means only the length
of the password matters.
A negative credit number “-N” means the same as a positive number except that you must have at least that many or the candidate password will “fail” regardless of its overall score. For example, setting:
password required pam_cracklib.so dcredit=-1 ucredit=-1 minlen=8
password required pam_pwquality.so dcredit=-1 ucredit=-1 minlen=8
ocredit at the
default value of 1) will require all passwords to have at least one
digit and at least one uppercase letter.
So “Foobar” will fail even though its score is 8
(6 + 1 + 1).
But “Fo0bar” (note the zero) will pass this test (its
score is 6+1+1+1=9, and it has the required 1 digit).
Another cracklib/pwquality setting is
difok” (note the single “f”).
It determines how many characters must be different (inserted, removed, or
replaced) from your old password.
The default is 1 for pam_pwquality on Fedora (although the man page says it is
“5”), which means your new password must
have at least one character not present in the old password or be one character
(It knows you previous password since you enter it when running the
passwd command. For older passwords, it only knows
their hashes, so this setting only looks at your current password.)
difok default can be set in the
Note a bug(?) in these modules
won't allow you to set a new password the
same as your current one, even if the value of
difok is zero.
To make the system remember old passwords, you need to add an
argument of “
remember=N” to the
pam_unix.so module (the one for the
password” context, not the one for
(Modern systems often have a
pam_pwhistory module, but either
seems to work.)
Try adding “
remember=3” and then change your
password a few times.
Then examine the
(Note, if using a single sign-on system such as LDAP
or Kerberos, password history doesn't work since the old hashes are only
saved on the local system.
Making this work properly would require a lot of changes; this is unlikely
to happen anytime soon.)
Cracklib/pwquality has a number of options that can be used
to support different policies, such as
See the Linux PAM documentation for cracklib/pwquality
for a list of all options you can use.
(Also, test that your policy works as expected!)
PAM is powerful but difficult, which is why it is so important to understand how to use it correctly to enforce security policies. By controlling which modules are used, their options, the order of modules, and which control-flags are used, you have the flexibility to enforce any security policy you can imagine. You can use the more complex configuration file syntax for even more precise control. (You can read about that if you want to go beyond the simple syntax discussed in this tutorial.) You can even write your own modules (or you can hire someone to do so).
Defining, implementing, and auditing security policies is a common and vital task of the Unix/Linux system administrator. You should become familiar with the standard PAM modules on your system so you will have an idea of the sort of policy you can use PAM to enforce. From there you should read the other documentation found at linux-pam.org. (This was formerly kept at www.kernel.org/pub/linux/libs/pam/.)