Technical post – understanding PAM, Pluggable Authentication Modules for Linux

PAM is one of the Linux components you probably already heard of. You know that it is used someway to authenticate users. You don't exactly know how it works neither how to configure it, but at the very bottom of the todo list you made a few years ago, there's the line "understand how PAM works" written, so you will get it eventually!

I had to understand PAM to configure the torrents InstantApp of Scaleway. You can use this app to create a C1 server in one click. It contains:

  • rTorrent to download torrent files.
  • ruTorrent, a pretty cool web interface to visualize and manage your downloads.
  • a fancy web page to list your downloaded files using h5ai.

I also wanted to install the FTP server vsftpd to allow the user to download his/her files from his favorite FTP client.

The web interface of the torrents InstantApp is protected by basic authentication (i.e. credentials are generated with htpasswd -c <filename> <username>) and I want to setup vsftpd to use this htpasswd file for authentication too.

PAM is a pain to understand and configure

Note that even if this tutorial explains how vsftpd is using PAM, the concepts are the same if you need to configure other softwares.

PAM authentication lifecycle

When you read some documentation about PAM, it's often explained how to configure it and it's quite... complicated. Let's try another way, and explain first how vsftpd uses PAM to handle authentication. We'll discuss the configuration files a little bit later.

In /etc/vsftpd.conf you will find pam_service_name=vsftpd. It means vsftpd uses the PAM service named vsftpd to perform authentication (in other words, it uses PAM configured by /etc/pam.d/vsftpd).

The authentication process is done in four steps:

  • first, vsftpd calls pam_authenticate to authenticate the user. PAM requires the user to provide an authentication token depending upon its configuration, usually this is a password, but could also be a finger print.
  • if it succeeds, vsftpd calls pam_acct_mgmt. PAM determines if the user's account is valid. It checks for the authentication token and account expiration and verifies access restrictions.
  • if it succeeds and SESSION_SUPPORT=YES in vsftpd.conf (default is NO), vsftpd calls pam_open_session. PAM sessions are used to do things that need to be done for the user before/after they can be given a service, for instance mounting directories.
  • finally, vsftpd calls pam_close_session to close the PAM session.

Each step (authentication, account management and session management) corresponds to a PAM type, named auth, account and session. Another type exists, password, useful to update the authentication token associated with the user but won't be discussed here, though after this blog post you should be able to read and understand the manual of pam.conf easily if you need to use it.

PAM configuration

PAM configuration files are located in /etc/pam.d. Each line (called rule) is composed as follow:

type control module-path module-arguments

For example the following rule is successful only if the username is not in /etc/ftpusers:

auth required pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed

Let's see what is the meaning of each part:

  • we saw type previously. It can be auth, account, password or session depending on which step you want to configure.
  • control indicates if the module should fail or succeed in its authentication task. Since the syntax is a bit more complex, we will discuss what it can contain just after.
  • module-path is the PAM module used to perform the action. A lot of PAM modules exist. For example, pam_listfile.so is used to allow or deny the access if the username is (or is not) in a text file ; and pam_unix.so is used to ask password and compare it against /etc/shadow. Note that certain modules cannot be used for every type. For instance, the module pam_shells.so which allows access to the system if the users shell is listed in /etc/shells can only be used for the types auth, account and password.
  • Finally, module-arguments are the arguments given to the module. For example, it could be item=user sense=deny file=/etc/ftpusers onerr=succeed for pam_listfile.so. You need to read the module documentation to understand the meaning of each parameter.

For the authentication process to succeed, the set of rules for each type must be successful. First, auth rules are processed, then account, then optionally session rules.

There is a way to control the behavior of a rule, and tell PAM "if this rule fails, then ignore it and go to the next one" or "if this rule succeeds, skip the next one and execute the one after" or "if this rule fails, do not process the next rules and return an error immediately to the application". This is what control is for.

control format in a PAM rule

control is a square-bracketed selection of value=action pairs, for example [success=ok new_authtok_reqd=ok ignore=ignore default=bad].

value can be one of these: success, cred_unavail, acct_expired, or default (and actually muuuuuuch more, everything is detailed in pam.conf). It allows to configure the behavior of the rule if the module returns a success, or if it returns that credentials are unavailable, or... you get the idea. default is used to configure the behavior of the values not explicitely mentionned.

action defines what to do if the PAM module returns value. It can be:

  • ignore to prevent returning an error to the application if the PAM module fails. In our case, the application is vsftpd, and we ignore when the authentication using the .htpasswd file fails to let later rules decide if we should grant access.
  • done to return the current status to the application, and stop processing further rules.
  • N (an unsigned integer) to skip the next N rules..

action can also be bad, die or ok.

Last thing about control: the square-bracket syntax is hard to read and you can use required (equivalent to [success=ok new_authtok_reqd=ok ignore=ignore default=bad]), requisite, sufficient or optional instead.

Everything is detailed in the man of pam.conf ;)

The final PAM configuration file

From now, you should be able to understand the configuration file.

# Ensure the FTP username is not in /etc/ftpusers
auth    required        pam_listfile.so item=user sense=deny file=/etc/ftpusers onerr=succeed

# If credentials match what is in the htpasswd file, return 
# success and do not process the other rules
auth    sufficient  pam_pwdfile.so pwdfile=/var/www/credentials debug

# Always return success. Note the type `account` will only
# be called if `auth` previously returned a success.
account sufficient  pam_permit.so

# Standard PAM includes, to authenticate using /etc/passwd.
@include common-account
@include common-session
@include common-auth

# Ensure the user has a shell in /etc/passwd.
auth    required        pam_shells.so  

Bonus time! Our /etc/pam.d/vsftpd and /etc/vsftpd.conf files are on github!

Author image

Julien Castets

DevOps at Scaleway, I'm also known as niluje, brmzkw and jcastets http://www.brmzkw.info