BSD DevCenter
oreilly.comSafari Books Online.Conferences.


FreeBSD Basics PAM

by Dru Lavigne

The previous article in this series examined an authentication method known as OTP (or One Time Passwords). Your FreeBSD system supports several types of authentication methods; you can choose which type your users are subject to by configuring something known as PAM, or Pluggable Authentication Modules.

As the name suggests, PAM consists of many modules. You can see which modules were installed with your system by issuing this command:

$ ls /usr/lib |grep pam_

Note that each module ends in so and has a name that gives some indication of what that module is responsible for.

"Pluggable" means you have great flexibility. The entire framework already exists; you merely choose which portions of the framework you wish to implement. It also implies that one can "plug in" the desired module. Each module can be added or removed by simply adding or deleting a remark or changing a keyword in a configuration file.

If you are new to PAM, you will find excellent information regarding FreeBSD's implementation, written by the very person in charge of the implementation. Alternatively, if you installed the docs/ directory when you installed FreeBSD, you'll find the same information on your hard drive:

$ ls /usr/share/doc/en_US.ISO8859-1/articles/pam

PAM uses some terminology that I've summarized into the following tables. First, PAM has been divided into four groups known as facilities. Each group provides at least one function, known as a primitive. Table 1 matches each primitive to its facility and includes a brief description of the functionality provided by that primitive:

Table 1: Four Facilities Divided Into Six Primitives

authpam_authenticateAuthenticates user.
 pam_setcredEstablishes UID, GID, resource limits.
accountpam_acct_mgmtTime of day, server load.
sessionpam_open_sessionRecord entry in utmp/wtmp, start SSH agent.
 pam_close_sessionSame as above, but when session closes.
passwordpam_chauthtokCheck for password expiry, easily-guessable password.

Next, PAM uses control flags to determine which authentication scheme or schemes to apply to a user. For now, I've summarized these flags in Table 2. Don't worry if this doesn't make sense; it will become more clear when we work through a configuration example.

Table 2:PAM's Control Flags

Control FlagsBehavior
requiredThis line must succeed.
requisiteRequest is immediately denied if this line fails.
sufficientRequest is immediately allowed if this line succeeds.
optionalIt's okay if this line fails.

Now that we're aware of the terminology used by PAM, we're ready to take a closer look at its configuration. This will vary depending upon whether you are using FreeBSD 4.x or 5.x, so I will demonstrate both. As of the time of this writing, FreeBSD 4.7 is considered STABLE and 5.0 is considered CURRENT. If you're unfamiliar with the difference between the two, an explanation can be found here and in the early adopter's guide.

Also in FreeBSD Basics:

Fun with Xorg

Sharing Internet Connections

Building a Desktop Firewall

Using DesktopBSD

Using PC-BSD

The upshot is that you don't want to install version 5.0 on your main machine until it has become STABLE and the number has changed to at least 5.1. The FreeBSD site will have an announcement when this occurs. Until then, you'll notice that my articles will mention both FreeBSD 4.x and 5.x, to help you through the transition period. If you are lucky enough to have a spare computer to use as a test machine, install FreeBSD 5.0 to give yourself time to play with its many new features. However, if you only have one computer, you can install FreeBSD on, wait until FreeBSD 5.1 before upgrading from version 4.x.

Having said all of that, one of the features of FreeBSD 5.x is greatly-improved PAM support. For one, the type of PAM has changed from Linux-PAM to OpenPAM.

I'll start by showing you how to configure PAM on a FreeBSD 4.x system, then move on to show you the changes with 5.0.

In FreeBSD 4.x, the PAM configuration file is /etc/pam.conf. I won't display the entire file here, as it starts off with about two pages of comments. Even though the comments repeat the information in the above tables, they are well worth reading on your own. Once you get past the comments, you'll see this section:

# If the user can authenticate with S/Key, that's sufficient; 
# allow clear password. Try kerberos, then try plain unix password.
login     auth      sufficient
login     auth      sufficient	              no_fake_prompts
#login    auth      required
login     auth      requisite
#login    auth      sufficient           try_first_pass
#login    auth      sufficient                 try_first_pass
login     auth      required                 try_first_pass
login     account   required
login     password  required
login     session   required

Each line in this section starts with the word login, as this section affects the login service. This section configures how a person will authenticate when they receive a login prompt. Let's see if we can work out the syntax.

First, three of those lines are commented out, as they begin with a #. This means that opieaccess and both versions of Kerberos aren't used by default. Second, each line in the pam.conf file is divided up as follows:

service   facility   control flag   module name   module arguments

Notice that the service is login, which supports all four facilities: auth, account, password, and session. Let's concentrate on the auth facility for a moment. There are seven listed ways a user can be authenticated: with s/key, OPIE, opie_access, a cleartext password, Kerberos IV, Kerberos 5, and the traditional Unix password authentication system.

The control flags determine which of the seven authentication methods a user is subject to. It's important to understand how these control flags interact with each other before you start editing this file. The lines are read in order, but some control flags tell PAM to read on to the next line, while other control flags tell PAM to stop reading.

Related Reading

Practical UNIX and Internet Security
By Simson Garfinkel, Gene Spafford, Alan Schwartz

For example, in the default configuration, is required and is requisite. Notice from the chart that authentication will fail if a user doesn't meet requisite. That is, if a user types in the incorrect cleartext password, the login will fail. However, if the user types in the correct cleartext password, PAM will continue reading. Since there aren't any other requisite lines and Unix password authentication is required, the correct cleartext password will be accepted as the user's authentication method.

Now, note the lines that use sufficient. If a user chooses to use an authentication method labeled as sufficient and their login attempt succeeds, PAM will stop reading and accept the authentication. However, a user is not required to authenticate using a method marked as sufficient. We saw this behavior when we configured OPIE. Since is sufficient, the user can log in with their OTP, if they choose to do so. If they give the correct challenge, the login will be successful and they won't be prompted for any further login information. If the user instead decides not to use OTP, she will be prompted to input the requisite cleartext password.

Now move down to the last four lines in this section. Notice there is a line for each facility and each line is required. If you ever change a line in a PAM configuration file, double check that the last line for each listed facility is required.

If you take a quick peek through the rest of /etc/pam.conf, you'll see sections for various services: ftpd, sshd, telnetd, xserver, xdm, gdm, imap, pop3, and other. This gives you the flexibility of specifying different authentication schemes for different services. If a user happens to connect to a FreeBSD system using a service not mentioned in the file, they will be subject to the other section, which by default requires a Unix password:

# If we don't match anything else, default to using getpwnam().
other    auth       required       try_first_pass
other    account    required       try_first_pass

The OpenPAM used in FreeBSD 5.x follows the same logic, but adds more modules and lays out the configuration slightly differently. If you try this command on a FreeBSD 5.0 system, you'll receive many more PAM modules:

ls /usr/lib |grep pam_

You'll also find that the 4.x modules have been included for backwards compatibility:

ls /usr/lib/compat |grep pam_

OpenPAM also supports /etc/pam.conf for backwards compatibility; however, this file isn't included for you. Instead, you should use the new layout:

$ ls /etc/pam.d
README     imap     other     rsh     xdm
ftp     kde     passwd     sshd     xserver
ftpd       login    pop3      su
gdm     rexecd      telnetd

Notice that each service in the old style /etc/pam.conf is now a separate file in the pam.d directory. The README file is the former comment section, and it has changed slightly, so yes, you should read it. In addition to the many new modules, more services have been added. The files themselves are identical to /etc/pam.conf, except the service name is missing as it is now the name of the file. For example, this line in /etc/pam.conf:

login    auth    sufficient    no_fake_prompts

is now this line in /etc/pam.d/login:

auth    sufficient    no_warn no_fake_prompts

Before you go about changing the default files for either type of PAM, you should be aware that PAM is a work in progress. I would highly recommend that you create a test account and be prepared for some experimentation. From one virtual terminal, make a change to the configuration file as the superuser. Then try to log in to another virtual terminal as the test user to see if your changes yield the intended result. This way if you come across any unexpected behavior, you can simply go back to the terminal where you changed the configuration file and undo the change.

As an example, let's see how one would go about always forcing users to use their OTP password at the login prompt. man pam_opieaccess gives a hint on how to take away a user's choice and force them to log in using OTP:

	To properly use this module, pam_opie(8) should be marked 
	``sufficient'', and pam_opieaccess should be listed right below it 
	and marked ``requisite''.

It also indicates how this change will affect your users:

 The authentication component (pam_sm_authenticate()), returns 
    PAM_SUCCESS in two cases:

        1.   The user does not have OPIE enabled.

        2.   The user has OPIE enabled, and the remote host is listed as a
	       trusted host in /etc/opieaccess, and the user does not have a 
	       file named opiealways in his home directory.

        Otherwise, it returns PAM_AUTH_ERR.

Let's compare those manpage hints to the relevant lines in /etc/pam.conf on a FreeBSD 4.7 system:

login    auth    sufficient
login    auth    sufficient                no_fake_prompts
#login   auth    required
login    auth    requisite
login    auth    required                try_first_pass

Depending upon when you installed FreeBSD, your line may say required instead of requisite. This is a typo in pam.conf, as the manpage is correct. I'll change that line so it now looks like this:

login    auth    requisite

Now, from another terminal, I'll try to log in as the test user. Instead of giving the OTP password, I'll try to give the reusable password for this account:

login: test
otp-md5 497 dh0908 ext
Password: (here I typed in the reusable password)

Hmmmm. At first glance, it looks like the configuration change failed to enforce OTP passwords, as the user successfully logged in using a reusable password. Better take another look at that section of the manpage:

	2.   The user has OPIE enabled, and the remote host is listed as a
	     trusted host in /etc/opieaccess, and the user does not have a 
	     file named opiealways in his home directory.

I wonder if it has something to do with that file opiealways? There's no manpage for it, so I went to my good friend and searched for opiealways. The very first hit brought me to the diary of OpenPAM's implementer, which explained that the presence of this file will always force a user to use OTP. So, as the test user, I created that empty file in my home directory. Then I logged out and tried to log back in without using OTP:

$ touch .opiealways
$ exit
login: test
otp-md5 497 dh0908 ext
Password: (here I typed in the reusable password)
pam_opieaccess: pam_sm_authenticate: Refused; 
                remote host is not in opieaccess
Login incorrect

Voila, by simply removing a remark in the PAM configuration file and instructing the user to touch .opiealways, that user will now always be forced to use OTP.

Being the paranoid type, I also tested that the configuration change didn't adversely affect users who don't use OTP. I logged in as a regular user, received the regular login prompt, and successfully logged in after inputting the correct reusable password. I carried the test one step further by creating a .opiealways file in a regular user's home directory. Since the user wasn't in the OTP database, that file did not affect the user's login. However, should the user in the future add themselves to the OTP database, the presence of that file will force them to use OTP.

This behavior can simplify things, if you plan on creating new user accounts that may decide to use OTP. Create the following file:

$ touch /usr/share/skel/dot.opiealways

Note that this skeleton file will only be inherited by new users you create. It won't affect existing user accounts.

This should get you started on your own PAM experiments. I will be writing about some of the new PAM modules later on this year, once FreeBSD 5.x has gone stable.

Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.

Read more FreeBSD Basics columns.

Return to the BSD DevCenter.

Sponsored by: