PAM (Pluggable Authentication Modules) is an abstraction layer that enables authentication between a variety of services.
PAM divides module functionality into different categories depending on which part of the process they are involved in. Here is a brief explanation of the categories:
Area | Description |
---|---|
Authentication | The authentication modules validate the user's authentication credentials. This means it checks if the user can supply valid credentials. |
Account | These modules are responsible for deciding if the account that is trying to sign in has access to the resources that it is requesting at this time. PAM allows you to specify controls that can deny or allow users based on predetermined criteria. |
Session | These modules establish the environment that will be built up and torn down after user log in or log off. Session files can determine which commands need to be run to prepare the environment. |
Password | These modules are responsible for updating various services' authentication details. If a password needs to be changed for a service, this module can assist in communicating with the service and modifying the correct values. |
The first two of these module categories will be referenced every time a program successfully uses PAM for authentication. The session modules will be run if necessary after the first two. The password modules are accessed on-demand.
PAM configuration files are stored at /etc/pam.d.
Issue the following command:
which should display something like:
root@server1:~# sudo ls /etc/pam.d accountsservice chfn chsh common-auth common-session cron newusers passwd ppp su atd chpasswd common-account common-password common-session-noninteractive login other polkit-1 sshd sudo root@serv
This directory generally has a configuration file for each application that will request PAM authentication. If an application calls PAM but there is no associated configuration file, the "other" configuration file is applied.
Inside the configuration files, there are usually calls to include the configuration files that begin with "common-". These are general configuration files whose rules should be applied in most situations.
The remaining modules that are referenced in the configuration files are located elsewhere.
When an application queries the PAM system for authentication, PAM reads the relevant PAM configuration file. The configuration files contain a list of PAM modules and how they should be handled. Each module is called in turn and each call to a module generates a success or failure result. Based on these values, the configuration file then decides if it should return an "authentication okay" message to the caller, or send it an authentication failure message. Configurations can fail at the return of the first failure from a called module, or alternative policies can be configured. For instance, a system may allow LDAP users to authenticate. If that fails, it may then check against the list of local users.
IMPORTANT:The lines of each configuration file are evaluated top to bottom, unless a line evaluation causes the rest of the configuration file to be skipped
The modules that are referenced in the PAM configuration files can be located by issuing the following command:
which should display something like:
root@server1:~# sudo ls /lib/*/security pam_access.so pam_faildelay.so pam_lastlog.so pam_mkhomedir.so pam_rhosts.so pam_stress.so pam_timestamp.so pam_wheel.so pam_debug.so pam_filter.so pam_limits.so pam_motd.so pam_rootok.so pam_succeed_if.so pam_tty_audit.so pam_xauth.so pam_deny.so pam_ftp.so pam_listfile.so pam_namespace.so pam_securetty.so pam_systemd.so pam_umask.so pam_echo.so pam_group.so pam_localuser.so pam_nologin.so pam_selinux.so pam_tally2.so pam_unix.so pam_env.so pam_issue.so pam_loginuid.so pam_permit.so pam_sepermit.so pam_tally.so pam_userdb.so pam_exec.so pam_keyinit.so pam_mail.so pam_pwhistory.so pam_shells.so pam_time.so pam_warn.so
The directory has a wide variety of modules which are available to use.
Almost all of the modules have man pages, which can describe their usage. They can be accessed by using something like man pam_mail.
Each line in a configuration file contains the following syntax, with each field delimited by white-space.
[service] type control module-path [module-arguments]
Files located within /etc/pam.d exclude the service field and, instead, name the configuration file after the application it serves. If there is no pam.d directory, a /etc/pam.conf file is needed instead, and the relevant application must be listed at the beginning of each line.
Area | Description |
---|---|
type | The kind of service that is provided. It is one of the four categories listed above (authentication, account, password, session). |
control | Specifies the action taken when it receives the return status of the module call. It can be any of these values (and can additionally take a more complex syntax, which won't be covered here):
|
module-path | The name of the PAM module to call. |
module-arguments | Optional parameters passed to the module. Sometimes these are necessary for the module to know what action to take if successful. |
Individual files may also reference other files that must be checked using the following syntax: @include config_file.
This will read in the entire configuration file, which is different from the "include" control type, which only reads in lines of the same type.
Lets investigate atd which is a scheduling daemon.
Issue the following command:
which should display something like:
# # The PAM configuration file for the at daemon # @include common-auth @include common-account @include common-session-noninteractive session required pam_limits.so session required pam_env.so user_readenv=1
The first three lines read in the common-auth, common-account, and common-session-noninteractive files to deal with their respective roles.
Then the pam_limits module is called, which checks the /etc/security/limits.conf file or the /etc/security/limits.d/ directory. This can be used to enforce limits on the number of users who can use a service at the same time, among other things.
The last line uses the pam_env module, which is used to set/unset environment variables. The user_readenv=1 part turns on the reading of the user specific environment file, /etc/security/pam_env.conf which specifies the environment variables to be set, unset or modified by pam_env(8). When someone logs in, this file is read and the environment variables are set according.
A more complete understanding of all of the checks taking place can be gained by looking at the files that are referenced.
Lets investigate the common-auth config file.
Issue the following command:
which should display something like:
# # /etc/pam.d/common-auth - authentication settings common to all services # # This file is included from other service-specific PAM config files, # and should contain a list of the authentication modules that define # the central authentication scheme for use on the system # (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the # traditional Unix authentication mechanisms. # # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. # To take advantage of this, it is recommended that you configure any # local modules either before or after the default block, and use # pam-auth-update to manage selection of other modules. See # pam-auth-update(8) for details. # here are the per-package modules (the "Primary" block) auth [success=1 default=ignore] pam_unix.so nullok_secure # here's the fallback if no module succeeds auth requisite pam_deny.so # prime the stack with a positive return value if there isn't one already; # this avoids us returning an error just because nothing sets a success code # since the modules above will each just jump around auth required pam_permit.so # and here are more per-package modules (the "Additional" block) # end of pam-auth-update config
Ignore the comment lines, i.e. the lines beginning with a # symbol. We are only interested in the lines shown in RED.
The first line calls the pam_unix module, which provides standard unix authentication configured through the /etc/nsswitch.conf file. Usually this just means checking the /etc/passwd and /etc/shadow files, as expected.
The nullok_secure argument being passed to the unix module specifies that accounts with no password are okay, as long as login information checks out with the /etc/securetty file.
The control field, which has [success=1 default=ignore] is the strange part of this example. It replaces the simplified required, sufficient, etc. parameters and allows for more fine-grained control. In this instance, if the module returns success, it skips the next "1" line. The default case, which handles every other return value of the module, results in the line being ignored and moving on.
The second line has the control value of requisite meaning that if it fails, the entire configuration returns a failure immediately. It also calls on the pam_deny module, which returns a failure for every call. This means that this will always fail. The only exception is when this line is skipped, which happens when the first line returns successfully.
The last line is required and calls the pam_permit module, which returns success every time. This simply resets the current pass/fail record at this point to ensure that there aren't some strange values from earlier.
Lets investigate the common-account config file.
Issue the following command:
which should display something like:
# # /etc/pam.d/common-account - authorization settings common to all services # # This file is included from other service-specific PAM config files, # and should contain a list of the authorization modules that define # the central access policy for use on the system. The default is to # only deny service to users whose accounts are expired in /etc/shadow. # # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. # To take advantage of this, it is recommended that you configure any # local modules either before or after the default block, and use # pam-auth-update to manage selection of other modules. See # pam-auth-update(8) for details. # # here are the per-package modules (the "Primary" block) account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so # here's the fallback if no module succeeds account requisite pam_deny.so # prime the stack with a positive return value if there isn't one already; # this avoids us returning an error just because nothing sets a success code # since the modules above will each just jump around account required pam_permit.so # and here are more per-package modules (the "Additional" block) # end of pam-auth-update config
Ignore the comment lines, i.e. the lines beginning with a # symbol. We are only interested in the lines shown in RED.
Almost everything in this file is similar to the one in the common-auth file. The first line calls for an account check with the pam_unix module.
Modules can perform different functions depending on the "type" of the call. For account calls, pam_unix checks that the account is not expired and is not controlled by time-based login restrictions.
If it passes, it skips the pam_deny call below it and then processes the permit rule at the end. If, on the other hand, it fails, it moves down to the deny line and exits with a failure.
Lets investigate the common-session-noninteractive config file.
Issue the following command:
which should display something like:
# # /etc/pam.d/common-session-noninteractive - session-related modules # common to all non-interactive services # # This file is included from other service-specific PAM config files, # and should contain a list of modules that define tasks to be performed # at the start and end of all non-interactive sessions. # # As of pam 1.0.1-6, this file is managed by pam-auth-update by default. # To take advantage of this, it is recommended that you configure any # local modules either before or after the default block, and use # pam-auth-update to manage selection of other modules. See # pam-auth-update(8) for details. # here are the per-package modules (the "Primary" block) session [default=1] pam_permit.so # here's the fallback if no module succeeds session requisite pam_deny.so # prime the stack with a positive return value if there isn't one already; # this avoids us returning an error just because nothing sets a success code # since the modules above will each just jump around session required pam_permit.so # The pam_umask module will set the umask according to the system default in # /etc/login.defs and user settings, solving the problem of different # umask settings with different shells, display managers, remote sessions etc. # See "man pam_umask". session optional pam_umask.so # and here are more per-package modules (the "Additional" block) session required pam_unix.so # end of pam-auth-update config
Ignore the comment lines, i.e. the lines beginning with a # symbol. We are only interested in the lines shown in RED.
The first three lines may look strange. You should be able to understand the program flow by this point, but they probably seem arbitrary and redundant. The first line is always successful, the next line is skipped ant the third line is always successful.
They are this way because many PAM configurations are auto-generated and would be modified to provide more substantial rules when additional PAM-aware authentication methods are available. This just creates a framework where new rules can be inserted to affect the program flow later on.
The fourth line is a call to the pam_umask module and is marked optional. This sets the file creation mask for the session. It will check a number of different file locations to try to find a relevant umask location.
The fifth line is a required call to the pam_unix module again. Because this is a "session" type of a call, the unix module behaves differently, yet again. In this case, it implements logging with the system's utilities.
Applications have to be written with PAM library support. To get a list of the applications on your system that can use PAM in some way, issue the following command:
which should display something like:
root@server1:~# ldd /{,usr/}{bin,sbin}/* | grep -B 5 libpam | grep '^/' /bin/login: /bin/su: /sbin/mkhomedir_helper: /sbin/pam_tally2: /usr/bin/check-language-support: /usr/bin/chfn: /usr/bin/chsh: /usr/bin/passwd: /usr/bin/pkexec: /usr/bin/screen: /usr/sbin/atd: /usr/sbin/chpasswd: /usr/sbin/cron: /usr/sbin/newusers: /usr/sbin/pam_getenv: /usr/sbin/pam_timestamp_check: /usr/sbin/sshd:
Specific applications can be checked for PAM functionality by issuing the following command:
For instance against /bin/login this would display something like:
root@server1:~# sudo ldd $(which /bin/login) | grep libpam libpam.so.0 => /lib/x86_64-linux-gnu/libpam.so.0 (0x00007fc03b3e6000) libpam_misc.so.0 => /lib/x86_64-linux-gnu/libpam_misc.so.0 (0x00007fc03b1e2000)
If this returns anything, then it can use PAM.
Copyright ShareWiz by Peter Roux