Page MenuHomeFreeBSD

pam_unix: Use suid root helper to authenticate
Needs RevisionPublic

Authored by felix_palmen-it.de on Feb 19 2022, 9:51 AM.

Details

Reviewers
des
cy
Summary

Only when running with an effective uid != 0 and a real uid matching the
user to authenticate, delegate password checking to the new suid root
helper in /usr/libexec/pam_unix-helper.

Test Plan

As user_a, with both user_a and user_b being normal, unprivileged users:

compile pamcheck.c:

#include <sys/types.h>
#include <security/pam_appl.h>
#include <security/openpam.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc != 2)
    {
	fputs("usage: pamcheck user\n", stderr);
	return 1;
    }

    pam_handle_t *pamh = 0;
    struct pam_conv conv = { openpam_ttyconv, 0 };
    int rc = pam_start("system", argv[1], &conv, &pamh);
    if (rc != PAM_SUCCESS)
    {
	fprintf(stderr, "%s\n", pam_strerror(pamh, rc));
	return 1;
    }
    rc = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK);
    const char *result = pam_strerror(pamh, rc);
    pam_end(pamh, rc);
    fprintf(stderr, "pam_authenticate: %s\n", result);
    return 0;
}

run ./pamcheck user_a, type user_a's password -> should indicate success.
run ./pamcheck user_a, type a random password -> should indicate failure.
run ./pamcheck user_b, type user_b's password -> should indicate failure.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint OK
Unit
No Unit Test Coverage
Build Status
Buildable 44512
Build 41400: arc lint + arc unit

Event Timeline

zarychtam_plan-b.pwste.edu.pl added inline comments.
lib/libpam/modules/pam_unix/pam_unix.c
351–352

Can it be extended to hold also password change management?

lib/libpam/modules/pam_unix/pam_unix.c
351–352

As discussed on IRC, this refers to the problem addressed in https://reviews.freebsd.org/D27656

It might be possible to enable password changes as non-root as well, maybe using the same helper, maybe using another one. I think this should be a followup change, to keep complexity manageable.

Helper only for self-authentication

Only use the helper when the real uid matches the uid from the password
database.

felix_palmen-it.de edited the test plan for this revision. (Show Details)
felix_palmen-it.de added a reviewer: des.
cy requested changes to this revision.May 2 2022, 5:08 PM

Agreed. No.

The other option might be to create a port that would provide an alternate pam_unix.so with an accompanying daemon. Or possibly add a linux-pam port. Either option is ugly and not recommended either.

This revision now requires changes to proceed.May 2 2022, 5:08 PM
In D34322#795736, @cy wrote:

Agreed. No.

Either option is ugly and not recommended either.

I find it extremely surprising that pam_unix.so requires root privileges to function. I mean, I do understand that performing this sort of authentication requires read access to /etc/master.passwd, but you're also saying that separate suid helper program is also ugly. How an unprivileged process is supposed to authenticate a user, then? Are you saying that it shouldn't ever want such a thing?

Why is this surprising? /etc/master.passwd is 0600 (or we repeat the mistakes of the 1980's and 1990's again). pam_unix.so is loaded into and runs in the process's own address space under the UID of the user, a user who must not have read access to /etc/master.passwd (FreeBSD) or /etc/shadow (Linux, Solaris).

Originally passwords were stored in /etc/passwd. Anyone could read it and anyone could crack it. A customer (quasi government entity) of mine about 20 years ago ran server for high school students on a SunOS 4.1.3 machine. The students had a captive shell but could easily break out of it to gain shell access. SunOS 4 didn't support /etc/shadow. A student downloaded /etc/passwd and posted it on USENET. The box was rooted shortly after that.

This is why /etc/passwd was split into two creating /etc/shadow on SYSVR4 systems, TCB (Trusted Computing Base) on Tru64, and /etc/master.passwd on BSD. Linux implemented the SYSVR4 model.

In D34322#795767, @cy wrote:

Why is this surprising? /etc/master.passwd […]

From the purely technical perspective, there's nothing surprising at all, "modern" unix auth requires root privileges indeed.

But looking from the PAM perspective, IMHO, it *is* surprising. Specifications describe it as abstracting system authentication for use by applications through a common interface. Sure, there's no mention of "unprivileged" anywhere, but I think it's safe to assume that your normal application shouldn't run privileged. So I conclude it shouldn't be the application's job to work around this problem for unix authentication.

A complete solution would probably require some kind of local daemon, implementing stuff like rate limiting etc. Not sure it's worth the effort to even think about it. This here was an attempt to solve it for the majority of usecases (authenticating as "self") with minimal effort, which is the same thing Linux PAM is doing as well. I see how one can be opposed to this as well.

Still in my opinion, the current situation isn't really in the spirit of the PAM specs.

What Linux did was a hack. (Remember PAM was written by Sun Microsysystems 20, 25 years ago). Short of changing the spec or adding some kind of kernel interface the linux-pam maintainer implemented a hack.

Take a look at ports/security/pam_helper. It may be what you're looking for. It was built to allow gnome-screensaver to use PAM without root privilege.

In D34322#795788, @cy wrote:

What Linux did was a hack. (Remember PAM was written by Sun Microsysystems 20, 25 years ago). Short of changing the spec or adding some kind of kernel interface the linux-pam maintainer implemented a hack.

Take a look at ports/security/pam_helper. It may be what you're looking for. It was built to allow gnome-screensaver to use PAM without root privilege.

That's what we use in xscreensaver 6.02 (the version I just committed). External helpers are no longer options in 6.03 and later, as the code to support/call them got removed (it was already loudly deprecated).

unix_chkpwd in Linux-PAM doesn't count as an external helper in xscreensaver's eyes.

I'd also argue such an external helper is the much worse hack:

  • it addresses a technical problem that leaks through the abstraction on the consumer side
  • it executes the whole PAM dialog privileged (of course including whatever module is configured)
  • it even does it when it wouldn't be necessary (e.g. when using network services like winbind, ldap, ... to authenticate)

Also, I don't see why you'd need kernel support for a complete solution? Some service would sure do. But it would be an awful lot more complexity than this hacky little helper that only allows self-authentication and only for pam_unix.

In D34322#795736, @cy wrote:

The other option might be to create a port that would provide an alternate pam_unix.so with an accompanying daemon. Or possibly add a linux-pam port. Either option is ugly and not recommended either.

You don't need an alternate pam_unix(8). As I've already told Felix, you can invoke a hypothetical setuid helper using pam_exec(8).

In D34322#795906, @des wrote:

You don't need an alternate pam_unix(8). As I've already told Felix, you can invoke a hypothetical setuid helper using pam_exec(8).

Sure this can be used, but how is it less of a hack? I'd still say the fact that the caller of PAM functions *sometimes* needs root privileges, depending on which modules are configured, is, uhm, conceptually wrong.

On the more practical side of course: For "fixing" it at least for self-auth, this could be used without modifying base, just deliver a suitable suid-root helper for pam_exec as a port and require the admin to reconfigure e.g. the "xscreensaver" PAM service.

just deliver a suitable suid-root helper for pam_exec as a port and require the admin to reconfigure e.g. the "xscreensaver" PAM service.

That's what I've been saying all along, so what are we arguing about?

In D34322#796040, @des wrote:

That's what I've been saying all along, so what are we arguing about?

"Arguing"? Well, my argument is: this is just another workaround (which also comes with some risk, such a helper should really get thorough code reviews for security reasons). I'll happily start working on it if there's an agreement that this issue should NOT be fixed on a lower level, although I personally think it should...

I'll happily start working on it if there's an agreement that this issue should NOT be fixed on a lower level, although I personally think it should...

The correct solution is to replace the whole NSS + PAM mess with a unified identity and authentication service, but that's a huge amount of work (which I'd love to take on if someone is willing to pay for it)

In D34322#796042, @des wrote:

The correct solution is to replace the whole NSS + PAM mess with a unified identity and authentication service

I have to agree *this* is the correct and clean solution indeed. I won't volunteer for it either, cause I think I'm lacking necessary experience for writing such a service.

So, it'll be the workaround I guess. Hope I'll find at least someone for review once I came up with something. Abandoning this here ...

Let's see a proof of concept so we can give it a whirl with xscreensaver 6.03. From this discourse, this may help other screen lockers and desktop configurators that unflinchingly assume Linux-PAM's hack, ie implementation details including any helpers in PAM itself rather than externally.

In D34322#796042, @des wrote:

The correct solution is to replace the whole NSS + PAM mess with a unified identity and authentication service, but that's a huge amount of work (which I'd love to take on if someone is willing to pay for it)

Agreed on all counts. Assuming that third-party projects won't accept ("FreeBSD, get your shit together" --jwz from xscreensaver), it's also unsustainable to maintain local patches to call stuff outside of PAM, especially if the program architectures are not conducive to such.

Ok, here's some first code that seems to work for me, would be happy to get some input on it: https://github.com/Zirias/unix-selfauth-helper

Ok, with the patch from https://reviews.freebsd.org/D35169 applied, my new helper seems to work very well, I couldn't find any problems myself any more (added another commit with a few minor improvements).

If anyone would like to review, will be very welcome! I guess then I'll start preparing a port for it. But unfortunately, without the fix to pam_exec, there's no way to make it work :-(