Discussion:
Trying to think out a hack for NSS and pw(8)
Garrett Wollman
2016-09-09 20:04:40 UTC
Permalink
Presently, we have a bunch of machines under configuration management
(using Puppet, but that's not really relevant here). I'm hoping to
implement LDAP via nsswitch on these machines, but I've run into an
issue: the standard getpw*(3) mechanisms can't tell the difference
between users or groups in the local databases and those in the remote
LDAP database. We need Puppet to manage entries for users and groups
in the local database, without respect to what entries might be
imported from LDAP (because they are supposed to override the data
returned by LDAP). Puppet invokes pw(8) to actually perform the
modifications, but I suspect it also uses native code from the Ruby
standard library to actually do pre-modification lookups.

Looking at the code in both nss-pam-ldapd and libc, it seems like the
only plausible way to fix this is to add functionality to nsswitch
which would allow it to use different configurations depending on the
identity of the process invoking getpwnam(3) or getgrnam(3). Does
anyone have opinions on how this ought to be implemented, or indeed
how it could be implemented securely?

(As a side issue, the net/nss-pam-ldapd port completely ignores
account expiration dates. This bug is due to the fact that Linux has
this ships-in-the-night "shadow" mechanism, getspent(3), rather than
having it integrated in getpwent(3) like it should be, but the
ultimate upshot is that if you're using nss-pam-ldapd you can't rely
on shadowExpire attributes in the directory actually have an effect on
FreeBSD. I'll open a bugzilla issue about this.)

-GAWollman
Poul-Henning Kamp
2016-09-09 20:13:02 UTC
Permalink
--------
Post by Garrett Wollman
Puppet invokes pw(8) to actually perform the
modifications, but I suspect it also uses native code from the Ruby
standard library to actually do pre-modification lookups.
[...]
Looking at the code in both nss-pam-ldapd and libc, it seems like the
only plausible way to fix this is to add functionality to nsswitch
which would allow it to use different configurations depending on the
identity of the process invoking getpwnam(3) or getgrnam(3).
You want to add a futher layer of complications to the the already
far too complicated user/group/authentication code in FreeBSD,
just because you don't want to look at Puppets Ruby code ?

Really ?
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
***@FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
Garrett Wollman
2016-09-10 03:28:42 UTC
Permalink
Post by Poul-Henning Kamp
You want to add a futher layer of complications to the the already
far too complicated user/group/authentication code in FreeBSD,
just because you don't want to look at Puppets Ruby code ?
Um, no, that's not remotely what I wrote.

I've spent far more time than is useful looking at Puppet's Ruby code,
TYVM.

What I don't want to do is rewrite pw(8) *and* the Ruby standard
library to have their own passwd(5) implementations to be used just
for managing the sysadmin accounts on a server.

I could tolerate changing pw(8) to give it a "local" flag that means
only look at/manipulate the local files -- except that the C library
doesn't provide any sort of hook for that (yet). I'm proposing to
implement that hook. That would at least get me 70% of the way there.

-GAWollman
Mike Kelly
2016-09-09 21:07:10 UTC
Permalink
You may find that the best way to handle this is to disable enumeration of
your LDAP users in NSS.

For example, if you're using sssd for your LDAP NSS & PAM provider, it is,
in fact, disabled by default.

This means that calls to getpwent(3) will only end up enumerating the users
in your local files, and not those in LDAP. But, calls to getpwnam(3),
getpwuid(3), etc will return the details of a specific username or user id,
even if it's only present in LDAP.
Post by Garrett Wollman
Presently, we have a bunch of machines under configuration management
(using Puppet, but that's not really relevant here). I'm hoping to
implement LDAP via nsswitch on these machines, but I've run into an
issue: the standard getpw*(3) mechanisms can't tell the difference
between users or groups in the local databases and those in the remote
LDAP database. We need Puppet to manage entries for users and groups
in the local database, without respect to what entries might be
imported from LDAP (because they are supposed to override the data
returned by LDAP). Puppet invokes pw(8) to actually perform the
modifications, but I suspect it also uses native code from the Ruby
standard library to actually do pre-modification lookups.
Looking at the code in both nss-pam-ldapd and libc, it seems like the
only plausible way to fix this is to add functionality to nsswitch
which would allow it to use different configurations depending on the
identity of the process invoking getpwnam(3) or getgrnam(3). Does
anyone have opinions on how this ought to be implemented, or indeed
how it could be implemented securely?
(As a side issue, the net/nss-pam-ldapd port completely ignores
account expiration dates. This bug is due to the fact that Linux has
this ships-in-the-night "shadow" mechanism, getspent(3), rather than
having it integrated in getpwent(3) like it should be, but the
ultimate upshot is that if you're using nss-pam-ldapd you can't rely
on shadowExpire attributes in the directory actually have an effect on
FreeBSD. I'll open a bugzilla issue about this.)
-GAWollman
_______________________________________________
https://lists.freebsd.org/mailman/listinfo/freebsd-security
"
--
Mike Kelly
Benjamin Kaduk
2016-09-10 05:56:33 UTC
Permalink
Post by Garrett Wollman
Presently, we have a bunch of machines under configuration management
(using Puppet, but that's not really relevant here). I'm hoping to
implement LDAP via nsswitch on these machines, but I've run into an
issue: the standard getpw*(3) mechanisms can't tell the difference
between users or groups in the local databases and those in the remote
LDAP database. We need Puppet to manage entries for users and groups
in the local database, without respect to what entries might be
imported from LDAP (because they are supposed to override the data
returned by LDAP). Puppet invokes pw(8) to actually perform the
modifications, but I suspect it also uses native code from the Ruby
standard library to actually do pre-modification lookups.
Looking at the code in both nss-pam-ldapd and libc, it seems like the
only plausible way to fix this is to add functionality to nsswitch
which would allow it to use different configurations depending on the
identity of the process invoking getpwnam(3) or getgrnam(3). Does
anyone have opinions on how this ought to be implemented, or indeed
how it could be implemented securely?
It's a bit late here, but it sounds kind of like you want to be able to
set NSS_NONLOCAL_IGNORE [and have it do something useful]?
(https://debathena.mit.edu/nss_nonlocal/)

Unfortunately, I never got far enough in trying to port Athena to FreeBSD
to have looked at how portable nss_nonlocal is. But it is probably worth
looking at, for your case.

-Ben
Jan Mikkelsen
2016-09-10 07:31:02 UTC
Permalink
Hi,

We have system images under version control with password databases as part of the system image which get merged with system-specific password databases. Not exactly the same requirement but similar.

We manage the two separate databases using the -V option to pw, and then have a script to merge the two databases into the standard local database. This runs on boot to bring in changes from the system image build, and after a local system change to apply the change. The problem with your environment is probably that you’re calling getpwnam, etc., where you can’t specify which password database you want to use.

If you changed the code that should only view local changes to use “pw -V /path/to/local usershow” instead of calling getpw*(), a similar approach might be possible.

Regards,

Jan.
Post by Garrett Wollman
Presently, we have a bunch of machines under configuration management
(using Puppet, but that's not really relevant here). I'm hoping to
implement LDAP via nsswitch on these machines, but I've run into an
issue: the standard getpw*(3) mechanisms can't tell the difference
between users or groups in the local databases and those in the remote
LDAP database. We need Puppet to manage entries for users and groups
in the local database, without respect to what entries might be
imported from LDAP (because they are supposed to override the data
returned by LDAP). Puppet invokes pw(8) to actually perform the
modifications, but I suspect it also uses native code from the Ruby
standard library to actually do pre-modification lookups.
Looking at the code in both nss-pam-ldapd and libc, it seems like the
only plausible way to fix this is to add functionality to nsswitch
which would allow it to use different configurations depending on the
identity of the process invoking getpwnam(3) or getgrnam(3). Does
anyone have opinions on how this ought to be implemented, or indeed
how it could be implemented securely?
(As a side issue, the net/nss-pam-ldapd port completely ignores
account expiration dates. This bug is due to the fact that Linux has
this ships-in-the-night "shadow" mechanism, getspent(3), rather than
having it integrated in getpwent(3) like it should be, but the
ultimate upshot is that if you're using nss-pam-ldapd you can't rely
on shadowExpire attributes in the directory actually have an effect on
FreeBSD. I'll open a bugzilla issue about this.)
-GAWollman
_______________________________________________
https://lists.freebsd.org/mailman/listinfo/freebsd-arch
Loading...