Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

PAM is quite something. Normally you ignore it and it quietly gets on with the job. Then one day you find yourself deploying something like this on your laptop:

  %PAM-1.0

  auth  required                   pam_faillock.so      preauth
  auth  [success=3 default=ignore] pam_unix.so          try_first_pass nullok
  auth  [success=2 default=ignore] pam_winbind.so
  -auth [success=1 default=ignore] pam_systemd_home.so
  auth  [default=die]              pam_faillock.so      authfail
  auth  required                   pam_permit.so
  auth  required                   pam_env.so
  auth  required                   pam_faillock.so      authsucc

  -account [success=2 default=ignore]  pam_systemd_home.so
  account  [success=1 default=ignore]  pam_winbind.so
  account  required                    pam_unix.so
  account  optional                    pam_permit.so
  account  required                    pam_time.so

  -password [success=2 default=ignore] pam_systemd_home.so
  password  [success=1 default=ignore] pam_winbind.so
  password  required                   pam_unix.so sha512 shadow
  password  optional                   pam_permit.so

  session required  pam_limits.so
  session required  pam_unix.so
  session required  pam_winbind.so
  session optional  pam_permit.so
The syntax is quite terse and like nothing else. No idea why it insists on wasting characters though. auth could be au, account: ac, password: pa and session: se. Why on earth put pam_ on the front of the modules and .so on the end. Tut!

The winbind stuff is configured elsewhere in several places - /etc/samba/smb.conf and /etc/security/pam_winbind.conf (obviously).

In general it is good enough to keep a spare virtual console logged in as root whilst you play with PAM. Otherwise get some experience with say Gentoo and Arch and the like. Then you will have rather good system rescue skills. Keep a System Rescue CD/USB to hand ... boot, mount /, /boot, /dev, /sys etc, chroot ... fix whatever you broke and then reboot. Rinse, repeat. Or spin up a VM and snapshot/checkpoint it before experimenting.



If you want to play with PAM, the best thing to do is to create a test program which links to the PAM library and which uses a different PAM service name so you can play with a config file which is different from the ones which ssh, su, sudo, etc., rely upon. That way you don't have to worry about screwing up your system and not having a way to recover.

An example of such a test program can be found at http://pamtester.sourceforge.net. I haven't tried using it myself, but I have taken a quick look at the source code, and it appears legit, if a bit over-engineered. Creating a test driver program which links against libpam really isn't all that complex, especially if you use the "configure the program by editing /tmp/foo.c and recompiling" methodology. :-)


And the best part is that it supports conditional logic with goto's! [success=3] mean's jump three rules ahead. Which means you can't really modify this file without considering the whole thing.

This led Ubuntu to create /usr/share/pam-configs which have files like

    Name: SSS authentication
    Default: yes
    Priority: 128

    Auth-Type: Primary
    Auth:
            [success=end default=ignore]    pam_sss.so use_first_pass
    Auth-Initial:
            [success=end default=ignore]    pam_sss.so forward_pass
    Account-Type: Additional
    Account:
            sufficient                      pam_localuser.so
            [default=bad success=ok user_unknown=ignore]    pam_sss.so
    Session-Type: Additional
    Session-Interactive-Only: yes
    Session:
            optional                        pam_sss.so
    Password-Type: Primary
    Password:
            sufficient                      pam_sss.so use_authtok
    Password-Initial:
            sufficient                      pam_sss.so
to try and make something declarative. RHEL/CentOS went the authconfig route but both ended up saying to never ever touch anything in /etc/pam.d


Wait, is this why my arbitrary changes to /etc/pam.d on Ubuntu have resulted in failure?


Maybe! Rewriting PAM is usually only done when messing with packages but can be called manually if you drop files in there with your config management.

“Wow this could be really useful” you might think. “Where “is it documented?”

https://wiki.ubuntu.com/PAMConfigFrameworkSpec

“But where is the reference, how do I know what directives are even available?”


This is the part that really gets me about PAM. There really did need to be something where it sits, and the plugin approach is perfectly sound. (Aside: I hope the expressed horror at "plugins in C" is one of the satirical parts, because plenty of people really do have such a poor grasp of computing history.) On the other hand, the implementation of those basic ideas has always been plagued by inscrutable APIs/formats, poor documentation, and unnecessarily catastrophic failure modes - as shown in the talk itself, and some of the comments above. Actually working with PAM is almost as unpleasant as working with SELinux, and neither has to be so bad.


You can always take control back. I have a fair few Ubuntus lying around whilst I use Arch on my laptop and workstations.

Ubuntu has /etc/pam.d/common-auth which looks like the main module to define your intent. Strip out the comments and see what you have left - read the comments first! Copy the whole lot somewhere and login to another console with root rights. Now you can play.

What would you like to do?


It's important to be aware that this goto nonsense is not PAM. It's not in Solaris PAM nor in OpenPAM (the BSD's PAM, as used in macOS, FreeBSD, NetBSD, and DragonFly BSD.)

Inventing bizarre and unusual turing complete configuration languages is a GNU/Linux hobby - just look at UDev reals.


> both ended up saying to never ever touch anything in /etc/pam.d

As I've learned the hard way, at least keep a root shell open somewhere if you do...


Characters are cheap nowadays. I'd much rather it be readable and understandable than have a bunch of cryptic abbreviations.


It's not readable and understandable, though.

I have more experience with PAM than most Linux admins, I think, and yet I still have to refer to man pages or Google every time I need to do something with it. The keywords and options are already basically nonsense.


Just to say, if I'm reading a config file and see "pam_winbind.so", I have a much better idea of what's going on than if the same file says "winbind" instead.


You already know that it's PAM-related, since it's a PAM config file. What extra info does the `pam_` give you?

.so does give you some info (namely, that it's an external shared object), but I'm not entirely certain how that alone gives you any better idea what's going on: that shared object could do literally anything. You need to know how PAM uses the shared object to know what's going on.


> You already know that it's PAM-related, since it's a PAM config file. What extra info does the `pam_` give you?

The filename, obviously.


Not to mention that linux-pam's `[success=2 default=ignore]` isn't even standard, I think OpenPAM only has the five control flags required/requisite/sufficient/binding/optional. (One may reasonably despair as to the difference between "required" and "requisite".)

It's almost as if PAM were developed before the invention of the if-then-else construct in the 1950s.[0]

[0]: https://github.com/e-n-f/if-then-else/blob/master/if-then-el...


Originally pam.conf was envisioned to be quite simple. Say, about the number of lines in /etc/inetd.conf. It was only later that people started doing these really complex things, and most of that was because Linux distributions were shipping far more distributed computing components than was originally were envisioned in 1995.

Since ordering was critical in PAM config files, and it was presumed that typical sysadmins weren't going to be editing PAM config files, it had to ship with mentions of every single package that might require a PAM config file. And this is what caused it to get super complex --- and not very well documented, since the presumption was that only distro-engineers needed to understand it, and tech writers have always been underappreciated and underpaid for as long as I can remember in the field (and probably longer).


He's making a joke exactly about that.


I started playing around with PAM when I set up this new laptop.

I make use of the pam_u2f.so module to require a FIDO2 fob AND password for my logins.

I even configued it to have backup fobs allowed in case I lose my primary, secondary, etc. (which I store in exceedingly secure spaces).

It's great that somebody would need both my password & my FIDO2 to access my laptop and there's no clear indication at login that the FIDO2 is required first if it isn't plugged in.


> Why on earth put pam_ on the front of the modules and .so on the end

Because it uses dynamic linking of the shared libraries used for authentication.


I was being facetious.

The config file doesn't need to worry about the nuts and bolts. All of the PAM modules are named pam_xxxxx.so so the configuration file only needs to specify the name, ie the xxxxx. Also some parts of the configuration are abbreviated, eg: auth and other bits are not, eg: password.

Those "[success = n" things mean "skip this number of lines if this invocation succeeds. It's a pretty mad "if f(x) == true goto n" statement.

Begrudgingly I have to say that despite the oddness of it all, it is reasonably easy to follow what is going on when you understand the rules.


> All of the PAM modules are named pam_xxxxx.so so the configuration file only needs to specify the name, ie the xxxxx.

I would rather type a few extra characters so that it is blindingly obvious that "pam_foo.so" in the config file will load code from pam_foo.so in the filesystem.

Typing only "foo" would remove a little clutter, but it would also increase my cognitive load a little.


>> All of the PAM modules are named pam_xxxxx.so so the configuration file only needs to specify the name, ie the xxxxx.

> I would rather type a few extra characters so that it is blindingly obvious that "pam_foo.so" in the config file will load code from pam_foo.so in the filesystem.

> Typing only "foo" would remove a little clutter, but it would also increase my cognitive load a little.

Exactly. Sometimes magic like what the GP wants is evil. It sub-optimally trades a steeper learning curve for some too-small convenience. It's like buying a shiny new penny for a dollar.


> It's like buying a shiny new penny for a dollar.

That's bonk. PAM significantly simplified the ecosystem - at the time there were dozens specialized hack upon hack upon hack login suits such as

* login-otp

* login-shadow

* login-skey

* des-login

* login-rsa-otp

that implemented some of the functionality for some of the manipulations, sometimes on the same system. Some of them already used shared libraries and some of those shared libraries already used the names. Specifying loading paths fully was considered a bad idea because of how subsystems were installed on the deployed servers. The decisions about name collisions ( pam_ prefix ), following Sun's original specs ( some of the names of stages ), etc were made from those constraints. It needed to be deployable on the top of the existing login systems where the users would not be locked out because of some sort of a conflict.

PAM significantly simplified that messy ecosystem while being extremely system, which is why it won and remains the integral part of the ecosystem for twenty seven years.

But hey, this is open source -- don't like it? Rewrite it in Rust! Just remember that first you would need to make sure that Rust exists on all the platforms PAM has been used on.[0]

[0] Pam-static was created as during the first few releases Linux/Alpha did not have support for shared libraries. So there it was, Pluggable Authentication Modules which on Alpha did not have dynamic loaders.


>>>> All of the PAM modules are named pam_xxxxx.so so the configuration file only needs to specify the name, ie the xxxxx.

>> It's like buying a shiny new penny for a dollar.

> That's bonk. PAM significantly simplified the ecosystem...

That's not what I was talking about at all. I wasn't talking about PAM itself, but the commenter's impulse to use an abbreviated name of the module in the config rather than the module's actual name. PAM did that right by using the full name in my opinion.


I misunderstood. My apologies.


It is because when we wrote the parser for it our goal was to make it braindead simple.


Who is "we", here?


"We"

I suspect you have awoken the Dark Ones (errr the PAM devs)


Honestly if this is how you get in contact with the PAM devs I should have done this a lot sooner.


The Dark Lords are always here.

PAM is pretty odd but not that bad!


udev also suffers from a similar config not-quite-programming-language syntax.

My theory is that the authors of both didn't know about parser generators.


Considering that some of the people behind PAM had their hands in the writing/patching those parsers, I doubt it


A further serious answer for those unfamiliar, the .so files are all found in a PAM module search path. You can replace a search-path-relative path (pam_blah.so) with an absolute path to a .so file if you wish.

    auth required /etc/whatever/my_pam_module.so




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: