--- a/src/__nss_files_fopen.c
+++ b/src/__nss_files_fopen.c
@@ -28,31 +28,267 @@
  * and as a result programs like adduser do not work correctly anymore
  * under fakechroot.
  *
- * Adhemerval Zanella (azanella) argued on IRC:
- *
- *  > But another problem is the ship has sailed, so there are nss modules that
- *  > will bind to an external symbol. And there is not much we can do about
- *  > it. And since nss modules are most compat, I am not sure community will
- *  > be willing to move back. I think it will be better to add the interpose
- *  > logic of private symbols on fakechroot instead, it is ugly but it is
- *  > better than messing even more with the nss interface.
- *
- * Thus, instead of changing glibc, we instead wrap __nss_files_fopen.
+ * Starting with glibc 2.34 the __nss_files_fopen was moved from nss to
+ * libc.so and thus wrapping it with LD_PRELOAD has no affect anymore
+ * (see 6212bb67f4695962748a5981e1b9fea105af74f6).
  *
+ * So now we also wrap all the functions accessing /etc/passwd, /etc/group
+ * and /etc/shadow. This solution will ignore NIS, LDAP or other local files
+ * as potentially configured in /etc/nsswitch.conf.
  */
-#ifdef HAVE___NSS_FILES_FOPEN
 
+#include <gnu/libc-version.h>
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 32)
+
+#include <stdlib.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <shadow.h>
 #include "libfakechroot.h"
 
+/* getpwent, setpwent, endpwent, getpwuid, getpwnam */
+
+static FILE *pw_f;
+
+wrapper(getpwent, struct passwd *, (void))
+{
+	if (!pw_f) pw_f = fopen("/etc/passwd", "rbe");
+	if (!pw_f) return 0;
+	return fgetpwent(pw_f);
+}
+
+wrapper (getpwent_r, int, (struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp))
+{
+	if (!pw_f) pw_f = fopen("/etc/passwd", "rbe");
+	if (!pw_f) return 0;
+	return fgetpwent_r(pw_f, pwbuf, buf, buflen, pwbufp);
+}
+
+wrapper(setpwent, void, (void))
+{
+	if (pw_f) fclose(pw_f);
+	pw_f = 0;
+}
+
+wrapper(endpwent, void, (void))
+{
+	if (pw_f) fclose(pw_f);
+	pw_f = 0;
+}
+
+wrapper(getpwuid, struct passwd *, (uid_t uid))
+{
+	debug("getpwuid(\"%ul\")", uid);
+	FILE *f = fopen("/etc/passwd", "rbe");
+	if (!f) {
+		return NULL;
+	}
+	struct passwd *res = NULL;
+	while ((res = fgetpwent(f))) {
+		if (res->pw_uid == uid)
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getpwuid_r, int, (uid_t uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result))
+{
+	debug("getpwuid_r(\"%ul\")", uid);
+	FILE *f = fopen("/etc/passwd", "rbe");
+	if (!f) {
+		return errno;
+	}
+	int res;
+	while (!(res = fgetpwent_r(f, pwd, buf, buflen, result))) {
+		if (pwd->pw_uid == uid)
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getpwnam, struct passwd *, (const char *name))
+{
+	debug("getpwnam(\"%s\")", name);
+	FILE *f = fopen("/etc/passwd", "rbe");
+	if (!f) {
+		return NULL;
+	}
+	struct passwd *res = NULL;
+	while ((res = fgetpwent(f))) {
+		if (name && !strcmp(name, res->pw_name))
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getpwnam_r, int, (const char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result))
+{
+	debug("getpwnam_r(\"%s\")", name);
+	FILE *f = fopen("/etc/passwd", "rbe");
+	if (!f) {
+		return errno;
+	}
+	int res;
+	while (!(res = fgetpwent_r(f, pwd, buf, buflen, result))) {
+		if (name && !strcmp(name, pwd->pw_name))
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+/* getgrent, setgrent, endgrent, getgrgid, getgrnam */
+
+static FILE *gr_f;
+
+wrapper(getgrent, struct group *, (void))
+{
+	if (!gr_f) gr_f = fopen("/etc/group", "rbe");
+	if (!gr_f) return 0;
+	return fgetgrent(gr_f);
+}
+
+wrapper (getgrent_r, int, (struct group *gbuf, char *buf, size_t buflen, struct group **gbufp))
+{
+	if (!gr_f) gr_f = fopen("/etc/group", "rbe");
+	if (!gr_f) return 0;
+	return fgetgrent_r(gr_f, gbuf, buf, buflen, gbufp);
+}
+
+wrapper(setgrent, void, (void))
+{
+	if (gr_f) fclose(gr_f);
+	gr_f = 0;
+}
+
+wrapper(endgrent, void, (void))
+{
+	if (gr_f) fclose(gr_f);
+	gr_f = 0;
+}
+
+wrapper(getgrgid, struct group *, (gid_t gid))
+{
+	debug("getgrgid(\"%ul\")", gid);
+	FILE *f = fopen("/etc/group", "rbe");
+	if (!f) {
+		return NULL;
+	}
+	struct group *res = NULL;
+	while ((res = fgetgrent(f))) {
+		if (res->gr_gid == gid)
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getgrgid_r, int, (gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result))
+{
+	debug("getgrgid_r(\"%ul\")", gid);
+	FILE *f = fopen("/etc/group", "rbe");
+	if (!f) {
+		return errno;
+	}
+	int res;
+	while (!(res = fgetgrent_r(f, grp, buf, buflen, result))) {
+		if (grp->gr_gid == gid)
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getgrnam, struct group *, (const char *name))
+{
+	debug("getgrnam(\"%s\")", name);
+	FILE *f = fopen("/etc/group", "rbe");
+	if (!f) {
+		return NULL;
+	}
+	struct group *res = NULL;
+	while ((res = fgetgrent(f))) {
+		if (name && !strcmp(name, res->gr_name))
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+wrapper(getgrnam_r, int, (const char *name, struct group *grp, char *buf, size_t buflen, struct group **result))
+{
+	debug("getgrnam_r(\"%s\")", name);
+	FILE *f = fopen("/etc/group", "rbe");
+	if (!f) {
+		return errno;
+	}
+	int res;
+	while (!(res = fgetgrent_r(f, grp, buf, buflen, result))) {
+		if (name && !strcmp(name, grp->gr_name))
+			break;
+	}
+	fclose(f);
+	return res;
+}
+
+/* getspent, setspent, endspent, getspnam */
+
+static FILE *sp_f;
+
+wrapper(getspent, struct spwd *, (void))
+{
+	if (!sp_f) sp_f = fopen("/etc/shadow", "rbe");
+	if (!sp_f) return 0;
+	return fgetspent(sp_f);
+}
+
+wrapper(setspent, void, (void))
+{
+	if (sp_f) fclose(sp_f);
+	sp_f = 0;
+}
+
+wrapper(endspent, void, (void))
+{
+	if (sp_f) fclose(sp_f);
+	sp_f = 0;
+}
+
+wrapper(getspnam, struct spwd *, (const char *name))
+{
+	debug("getspnam(\"%s\")", name);
+	FILE *f = fopen("/etc/shadow", "rbe");
+	if (!f) {
+		return NULL;
+	}
+	struct spwd *res = NULL;
+	while ((res = fgetspent(f))) {
+		if (name && !strcmp(name, res->sp_namp))
+			break;
+	}
+	fclose(f);
+	return res;
+}
 
-wrapper(__nss_files_fopen, FILE *, (const char * path))
+wrapper(getspnam_r, int, (const char *name, struct spwd *spbuf, char *buf, size_t buflen, struct spwd **spbufp))
 {
-    char fakechroot_abspath[FAKECHROOT_PATH_MAX];
-    char fakechroot_buf[FAKECHROOT_PATH_MAX];
-    debug("__nss_files_fopen(\"%s\")", path);
-    expand_chroot_path(path);
-    return nextcall(__nss_files_fopen)(path);
+	debug("getspnam_r(\"%s\")", name);
+	FILE *f = fopen("/etc/shadow", "rbe");
+	if (!f) {
+		return errno;
+	}
+	int res;
+	while (!(res = fgetspent_r(f, spbuf, buf, buflen, spbufp))) {
+		if (name && !strcmp(name, spbuf->sp_namp))
+			break;
+	}
+	fclose(f);
+	return res;
 }
 
 #else
--- a/test/t/nss_files_fopen.t
+++ b/test/t/nss_files_fopen.t
@@ -3,7 +3,7 @@
 srcdir=${srcdir:-.}
 . $srcdir/common.inc.sh
 
-prepare 2
+prepare 4
 
 for chroot in chroot fakechroot; do
     if [ $chroot = "chroot" ] && ! is_root; then
@@ -13,6 +13,10 @@ for chroot in chroot fakechroot; do
         t=`$srcdir/$chroot.sh $testtree /bin/test-nss_files_fopen user 2>&1`
         test "$t" = "1337" || not
         ok "$chroot uid is" $t
+
+        t=`$srcdir/$chroot.sh $testtree getent group user 2>&1`
+        test "$t" = "user:x:1337:" || not
+        ok "$chroot getent group user is" $t
     fi
 done
 
--- a/test/testtree.sh
+++ b/test/testtree.sh
@@ -33,6 +33,8 @@ do
 done
 
 echo "user:x:1337:1337:user:/home/user:/bin/bash" > $destdir/etc/passwd
+echo "root:x:0:" > $destdir/etc/group
+echo "user:x:1337:" >> $destdir/etc/group
 
 for d in \
     /dev \
@@ -66,6 +68,7 @@ for p in \
     '/usr/bin/dirname' \
     '/usr/bin/env' \
     '/usr/bin/find' \
+    '/usr/bin/getent' \
     '/usr/bin/id' \
     '/usr/bin/ischroot' \
     '/usr/bin/less' \
