Testing NSS modules in glibc
The Name Service
Switch
(NSS) is the feature of many C libraries, including the standard Linux one
(GNU libc) and the standard Solaris one, that allows name lookup
routines to be implemented via plugins. "Name lookup" here refers to
things like usernames, host names, etc. When you run ls -l
, and the
ls
command maps numeric user IDs to usernames, the names are provided
by any module listed in the Name Service Switch's configuration. This
could be the files
module that looks at local files like
/etc/passwd
, the ldap
module that talks to a corporate LDAP server,
etc.
One of my half-forgotten side projects involves writing a new NSS module.
NSS is configured via the file /etc/nsswitch.conf
, which is systemwide
configuration. If I want to test my NSS module, I could install it
globally and reconfigure my system. But I started wondering if there was
a way to load an NSS module just for a single process under my control.
Since the process is running in my user account, I should be able to
reconfigure it, without affecting the rest of the system.
Turns out that it's possible in a somewhat hackish way. There's an
internal glibc function called __nss_configure_lookup
that overrides
NSS settings. If you're writing your own test program, you can just
call, e.g., __nss_configure_lookup("passwd", "files")
to force
all user lookups to go through libnss_files
. If you're using an
existing program, you can shoehorn this in by use of an LD_PRELOAD
:
#include <nss.h>
#include <stdlib.h>
static void __attribute__((constructor))
nsstest_ctor(void)
{
const char *db = getenv("NSSTEST_DB"), *config = getenv("NSSTEST_CONFIG");
if (db && config)
__nss_configure_lookup(db, config);
}
Compile with gcc -fPIC -shared -o nsstest.so nsstest.c
. Then you can
do things like this:
howe-and-ser-moving:/tmp geofft$ ls -ld ~
drwxr-xr-x 355 geofft root 34816 Apr 17 21:25 /afs/athena.mit.edu/user/g/e/geofft
howe-and-ser-moving:/tmp geofft$ LD_PRELOAD=./nsstest.so NSSTEST_DB=passwd NSSTEST_CONFIG=files ls -ld ~
drwxr-xr-x 355 40490 root 34816 Apr 17 21:25 /afs/athena.mit.edu/user/g/e/geofft
Since my account isn't in the files
database on this machine (it's in
hesiod
), my user ID can no longer be looked up if I restrict passwd
lookups to the files
database. A more straightforward way of testing
is using the getent
command that ships with glibc, which lets you ask
for a specific entry in a specific NSS database. For instance, both
files
and hesiod
have entries for the root
user:
howe-and-ser-moving:/tmp geofft$ LD_PRELOAD=./nsstest.so NSSTEST_DB=passwd NSSTEST_CONFIG=files getent passwd root
root:x:0:0:root:/root:/bin/bash
howe-and-ser-moving:/tmp geofft$ LD_PRELOAD=./nsstest.so NSSTEST_DB=passwd NSSTEST_CONFIG=hesiod getent passwd root
root:*:0:101:Wizard A Root,,,:/mit/root:/bin/csh
If you're writing your own NSS library, you'll also need to set
LD_LIBRARY_PATH
to point to the directory where it lives, since NSS
configuration just takes names, not full paths.