Blob Blame History Raw
--- ./lib/rpmchroot.c.orig	2012-11-07 12:55:24.000000000 +0000
+++ ./lib/rpmchroot.c	2014-02-20 12:50:05.360815211 +0000
@@ -66,6 +66,7 @@ int rpmChrootIn(void)
     } else if (rootState.chrootDone == 0) {
 	if (chdir("/") == 0 && chroot(rootState.rootDir) == 0) {
 	    rootState.chrootDone = 1;
+	    rpmugChroot(1);
 	} else {
 	    rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
 	    rc = -1;
@@ -91,6 +92,7 @@ int rpmChrootOut(void)
     } else if (rootState.chrootDone == 1) {
 	if (chroot(".") == 0 && fchdir(rootState.cwd) == 0) {
 	    rootState.chrootDone = 0;
+	    rpmugChroot(0);
 	} else {
 	    rpmlog(RPMLOG_ERR, _("Unable to restore root directory: %m\n"));
 	    rc = -1;
--- ./lib/rpmug.c.orig	2014-02-05 13:04:37.000000000 +0000
+++ ./lib/rpmug.c	2014-02-20 12:50:05.361815211 +0000
@@ -10,6 +10,47 @@
 #include "lib/rpmug.h"
 #include "debug.h"
 
+#if defined(__GLIBC__)
+
+static int inchroot;
+
+/*
+ * Unfortunatelly glibc caches nss/nscd data and there is no
+ * good way to flush those caches when we did a chroot(). Thus
+ * we need to parse /etc/passwd and /etc/group ourselfs.
+ */
+static int safe_lookup(const char * file, const char * name)
+{
+    FILE *fp;
+    int l;
+    char buf[4096], *p;
+
+    if (!name || !*name)
+	return -1;
+    l = strlen(name);
+    if ((fp = fopen(file, "r")) == 0)
+	return -1;
+    while ((p = fgets(buf, sizeof(buf), fp)) != 0) {
+	if (*p == '#')
+	    continue;
+	while (*p && (*p == ' ' || *p == '\t'))
+	    p++;
+	if (strncmp(p, name, l) != 0 || p[l] != ':')
+	    continue;
+	p = strchr(p + l + 1, ':');
+	if (!p)
+	    continue;
+	fclose(fp);
+	p++;
+	while (*p && (*p == ' ' || *p == '\t'))
+	    p++;
+	return atoi(p);
+    }
+    fclose(fp);
+    return -1;
+}
+#endif
+
 /* 
  * These really ought to use hash tables. I just made the
  * guess that most files would be owned by root or the same person/group
@@ -43,17 +84,28 @@ int rpmugUid(const char * thisUname, uid
 	    lastUnameAlloced = thisUnameLen + 10;
 	    lastUname = xrealloc(lastUname, lastUnameAlloced);	/* XXX memory leak */
 	}
-	strcpy(lastUname, thisUname);
 
-	pwent = getpwnam(thisUname);
-	if (pwent == NULL) {
-	    /* FIX: shrug */
-	    endpwent();
+#if defined(__GLIBC__)
+	if (inchroot) {
+	    int uid =  safe_lookup("/etc/passwd", thisUname);
+	    if (uid < 0)
+		return -1;
+	    lastUid = uid;
+	} else
+#endif
+	{
 	    pwent = getpwnam(thisUname);
-	    if (pwent == NULL) return -1;
+	    if (pwent == NULL) {
+		/* FIX: shrug */
+		endpwent();
+		pwent = getpwnam(thisUname);
+		if (pwent == NULL) return -1;
+	    }
+	    lastUid = pwent->pw_uid;
 	}
 
-	lastUid = pwent->pw_uid;
+	strcpy(lastUname, thisUname);
+	lastUnameLen = thisUnameLen;
     }
 
     *uid = lastUid;
@@ -86,18 +138,29 @@ int rpmugGid(const char * thisGname, gid
 	    lastGnameAlloced = thisGnameLen + 10;
 	    lastGname = xrealloc(lastGname, lastGnameAlloced);	/* XXX memory leak */
 	}
-	strcpy(lastGname, thisGname);
 
-	grent = getgrnam(thisGname);
-	if (grent == NULL) {
-	    /* FIX: shrug */
-	    endgrent();
+#if defined(__GLIBC__)
+	if (inchroot) {
+	    int gid =  safe_lookup("/etc/group", thisGname);
+	    if (gid < 0)
+		return -1;
+	    lastGid = gid;
+	} else
+#endif
+	{
 	    grent = getgrnam(thisGname);
 	    if (grent == NULL) {
-		return -1;
+		/* FIX: shrug */
+		endgrent();
+		grent = getgrnam(thisGname);
+		if (grent == NULL) {
+		    return -1;
+		}
 	    }
+	    lastGid = grent->gr_gid;
 	}
-	lastGid = grent->gr_gid;
+	strcpy(lastGname, thisGname);
+	lastGnameLen = thisGnameLen;
     }
 
     *gid = lastGid;
@@ -109,7 +172,7 @@ const char * rpmugUname(uid_t uid)
 {
     static uid_t lastUid = (uid_t) -1;
     static char * lastUname = NULL;
-    static size_t lastUnameLen = 0;
+    static size_t lastUnameAlloced = 0;
 
     if (uid == (uid_t) -1) {
 	lastUid = (uid_t) -1;
@@ -126,9 +189,9 @@ const char * rpmugUname(uid_t uid)
 
 	lastUid = uid;
 	len = strlen(pwent->pw_name);
-	if (lastUnameLen < len + 1) {
-	    lastUnameLen = len + 20;
-	    lastUname = xrealloc(lastUname, lastUnameLen);
+	if (lastUnameAlloced < len + 1) {
+	    lastUnameAlloced = len + 20;
+	    lastUname = xrealloc(lastUname, lastUnameAlloced);
 	}
 	strcpy(lastUname, pwent->pw_name);
 
@@ -140,7 +203,7 @@ const char * rpmugGname(gid_t gid)
 {
     static gid_t lastGid = (gid_t) -1;
     static char * lastGname = NULL;
-    static size_t lastGnameLen = 0;
+    static size_t lastGnameAlloced = 0;
 
     if (gid == (gid_t) -1) {
 	lastGid = (gid_t) -1;
@@ -157,9 +220,9 @@ const char * rpmugGname(gid_t gid)
 
 	lastGid = gid;
 	len = strlen(grent->gr_name);
-	if (lastGnameLen < len + 1) {
-	    lastGnameLen = len + 20;
-	    lastGname = xrealloc(lastGname, lastGnameLen);
+	if (lastGnameAlloced < len + 1) {
+	    lastGnameAlloced = len + 20;
+	    lastGname = xrealloc(lastGname, lastGnameAlloced);
 	}
 	strcpy(lastGname, grent->gr_name);
 
@@ -189,3 +252,16 @@ void rpmugFree(void)
     rpmugUname(-1);
     rpmugGname(-1);
 }
+
+void rpmugChroot(int in)
+{
+    /* tell libc to drop caches / file descriptors */
+    endpwent();
+    endgrent();
+    /* drop our own caches */
+    rpmugUid(NULL, NULL);
+    rpmugGid(NULL, NULL);
+#if defined(__GLIBC__)
+    inchroot = in;
+#endif
+}
--- ./lib/rpmug.h.orig	2014-02-05 13:04:02.000000000 +0000
+++ ./lib/rpmug.h	2014-02-20 12:50:05.362815211 +0000
@@ -15,4 +15,6 @@ int rpmugInit(void);
 
 void rpmugFree(void);
 
+void rpmugChroot(int in);
+
 #endif /* _RPMUG_H */