This is currently incomplete and has no links to it, so if I didn't send you a link to it and you still found it, I'm impressed!
I am, among other things, a sysadmin and an OpenSSH developer.
As a sysadmin, I was neutral to positive about PAM. Neutral because our environment (lots of individual machines on different networks separated by firewalls) didn't lend itself to the kind schemes that PAM is often used for (eg Kerberos, RADIUS), but positive because it seemed to provide a bunch of neat capabilities, even if we couldn't use it much.
Since mid-2003, I have done a lot of the work on OpenSSH's PAM interface, and have grown to really dislike PAM. It's not any single thing that makes it so difficult to work with (in the context of OpenSSH), but a number of things that compound to make life far harder than they ought to be.
The PAM API and the SSH protocol are a poor match, and this mismatch makes it tricky for an SSH server to support PAM. Niels Möller (the author of the SSH implementation lsh) has also noted this.
From my point of view, the main reasons are:
PermitEmptyPasswordsis set to
This is the biggest problem with the PAM architecture with respect
to an SSH implementation. The primary interface to the PAM functions
are blocking library calls, but the mechanism for interacting with the
user is the
conversation function, which is a callback.
When a PAM function, such as
pam_authenticate, is called,
the function does not return until the authentication has run to
completion and either succeeded or failed, but during this time the
conversation function may be called any number of times.
This is a big drawback for event-driven applications (such as
sshd): if an event requires a call to PAM, this call will
block until the PAM interaction is complete during which time
the event loop is not running. This is a massive problem if
the interaction with the user requires the event loop as it does
This could be improved greatly by implementing some kind of re-entrant conversation function.
The PAM conversation mechanism also means that the application's interface to PAM is about twice as complicated as it needs to be.
In Firewalls and Internet Security (1994), the authors discuss adding hooks to Unix authentication binaries and offer this advice: "we do not recommend doing this via a shared library; such facilities have been responsible for security problems on a number of different platforms." PAM was first introduced in Solaris 2.3 (release November 1993) as a private interface and in Solaris 2.6 (1997) as a public interface. The security implications of using shared libraries were known in that timeframe, but PAM uses them anyway.
The PAM application and PAM modules are at each other's mercy due to their shared address space. Programming errors in either can trash memory in the other, so there is no easy way to determine which is responsible for a problem, since it's quite possible that the place where it blows up is in no way related to the source of the error.
Along the same lines, because they're in the same address space
applications and modules are vulnerable to namespace collisions. This
risk can be reduced by using unique prefixes for functions and global
variables and making as many as possible
Loadable modules also bring with them a series of challenges resolving conflicts while dynamic linking (eg, if the application is linked against the system's libcrypt.so for crypt() and the module is linked against OpenSSL's libcrypto, which gets used?).
To be fair, running in the application's address space does provide some advantages over alternatives (such as separate helpers as used by BSD auth). For example, the PAM modules can perform kernel-level magic that will "stick" with the application (eg AFS modules can set a PAG). I think the disadvantages outweigh the advantages.
XSSO (pp 89) specifies that the message parameter passed to the conversation function is "a pointer to an array". Solaris PAM treats it as such, but LinuxPAM (and OpenPAM?) treat it as an array of pointers. The two are equivalent for a single message, but can blow up horribly for more. The LinuxPAM documentation recommends modules call the conversation function with only one message, or doubly-reference the structs so both methods work.
Solaris PAM and OpenPAM expect pam_setcred to be called before pam_open_session, whereas LinuxPAM expects the opposite.
The Solaris 8 pam_setcred(3PAM) man page says:
It is typically called after the user has been authenticated and after a session has been opened. See pam_authenticate(3PAM), pam_acct_mgmt(3PAM), and pam_open_session(3PAM).Whereas the LinuxPAM pam_setcred(3) man page:
This function is used to establish, maintain and delete the credentials of a user. It should be called after a user has been authenticated and before a session is opened for the user (with pam_open_session(3)).This seems to show up in assumptions made by third-party modules which only work with one order (Trusted HP-UX seems to be particularly picky).
There is little consistency between the module names and parameters
pam_unix.so usually implementes the
traditional Unix account semantics, but even this is not consistent
everywhere: Solaris 8 and up this is split into
This one is trivial but annoying because it's unnecessary. The PAM
application header file is
Except on Mac OS X, where in the interests of consistency it's
Solaris will not enforce password restrictions if the real uid of the calling process is 0, on the assumption that it's passwd being run as root. Conversely, AIX's pam_chauthtok() won't work at all if the real uid is not 0.
Some versions of LinuxPAM will not permit the changing of the
conversation function. The
[...]) call succeeds but the previous conversation is still
called. This has been observed with Redhat 9 (pam-0.75-48) and Fedora
Core 2 (pam-0.77-40), but does not occur with Debian 3.0 (...). This
can be demonstrated with this small test program. Note that even
though pam_set_item succeeded, pam_chauthtok still uses to old
conversation function. This been mentioned on the pam
list and reported as a Fedora
A PAM application may have to deal with any number of buggy modules. Some examples:
pam_convstructure, which seems to be present to allow a single conversation function to handle multiple concurrent authentication requests). Some modules, however, do not correctly handle this application data and pass NULL to the conversation function instead of the pointer.
Page last modified: $Date: 2022-05-25 $