File safeugid.diff of Package rpm

--- ./lib/fsm.c.orig	2010-06-04 12:47:34.000000000 +0000
+++ ./lib/fsm.c	2010-06-04 12:47:44.000000000 +0000
@@ -738,22 +738,26 @@ static int fsmMapAttrs(FSM_t fsm)
 
     /* this check is pretty moot,  rpmfi accessors check array bounds etc */
     if (fi && i >= 0 && i < rpmfiFC(fi)) {
+	rpmts ts = fsmGetTs(fsm);
 	mode_t finalMode = rpmfiFModeIndex(fi, i);
 	dev_t finalRdev = rpmfiFRdevIndex(fi, i);
 	time_t finalMtime = rpmfiFMtimeIndex(fi, i);
 	const char *user = rpmfiFUserIndex(fi, i);
 	const char *group = rpmfiFGroupIndex(fi, i);
+	int safe = rpmtsChrootDone(ts);
+	extern int unameToUid_safe(const char *, gid_t *, int);
+	extern int gnameToGid_safe(const char *, gid_t *, int);
 	uid_t uid = 0;
 	gid_t gid = 0;
 
-	if (user && unameToUid(user, &uid)) {
+	if (user && unameToUid_safe(user, &uid, safe)) {
 	    if (fsm->goal == FSM_PKGINSTALL)
 		rpmlog(RPMLOG_WARNING,
 		    _("user %s does not exist - using root\n"), user);
 	    finalMode &= ~S_ISUID;      /* turn off suid bit */
 	}
 
-	if (group && gnameToGid(group, &gid)) {
+	if (group && gnameToGid_safe(group, &gid, safe)) {
 	    if (fsm->goal == FSM_PKGINSTALL)
 		rpmlog(RPMLOG_WARNING,
 		    _("group %s does not exist - using root\n"), group);
@@ -775,8 +779,7 @@ static int fsmMapAttrs(FSM_t fsm)
 	if (fsm->mapFlags & CPIO_MAP_GID)
 	    st->st_gid = gid;
 
-	{   rpmts ts = fsmGetTs(fsm);
-
+	{
 	    /*
 	     * Set file digest (if not disabled).
 	     */
--- ./lib/misc.c.orig	2009-06-23 11:40:57.000000000 +0000
+++ ./lib/misc.c	2010-06-04 12:51:16.000000000 +0000
@@ -13,6 +13,42 @@ const char * const RPMVERSION = VERSION;
 
 #include "debug.h"
 
+/*
+ * 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;
+}
+
 /* unameToUid(), uidTouname() and the group variants are really poorly
    implemented. They really ought to use hash tables. I just made the
    guess that most files would be owned by root or the same person/group
@@ -20,11 +56,12 @@ const char * const RPMVERSION = VERSION;
    is looked up via getpw() and getgr() functions.  If this performs
    too poorly I'll have to implement it properly :-( */
 
-int unameToUid(const char * thisUname, uid_t * uid)
+int unameToUid_safe(const char * thisUname, uid_t * uid, int safe)
 {
 static char * lastUname = NULL;
     static size_t lastUnameLen = 0;
     static size_t lastUnameAlloced;
+    static int lastUnameSafe;
     static uid_t lastUid;
     struct passwd * pwent;
     size_t thisUnameLen;
@@ -37,6 +74,11 @@ static char * lastUname = NULL;
 	return 0;
     }
 
+    if (safe != lastUnameSafe) {
+	lastUnameLen = 0;
+	lastUnameSafe = safe;
+    }
+
     thisUnameLen = strlen(thisUname);
     if (lastUname == NULL || thisUnameLen != lastUnameLen ||
 	strcmp(thisUname, lastUname) != 0)
@@ -47,15 +89,21 @@ static char * lastUname = NULL;
 	}
 	strcpy(lastUname, thisUname);
 
-	pwent = getpwnam(thisUname);
-	if (pwent == NULL) {
-	    /* FIX: shrug */
-	    endpwent();
+	if (safe) {
+	    int uid = safe_lookup("/etc/passwd", thisUname);
+	    if (uid < 0)
+		return -1;
+	    lastUid = (uid_t)uid;
+	} else {
 	    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;
     }
 
     *uid = lastUid;
@@ -63,11 +111,18 @@ static char * lastUname = NULL;
     return 0;
 }
 
-int gnameToGid(const char * thisGname, gid_t * gid)
+int unameToUid(const char * thisUname, uid_t * uid)
+{
+    return unameToUid_safe(thisUname, uid, 0);
+}
+
+
+int gnameToGid_safe(const char * thisGname, gid_t * gid, int safe)
 {
 static char * lastGname = NULL;
     static size_t lastGnameLen = 0;
     static size_t lastGnameAlloced;
+    static int lastGnameSafe;
     static gid_t lastGid;
     size_t thisGnameLen;
     struct group * grent;
@@ -80,6 +135,11 @@ static char * lastGname = NULL;
 	return 0;
     }
 
+    if (safe != lastGnameSafe) {
+	lastGnameLen = 0;
+	lastGnameSafe = safe;
+    }
+
     thisGnameLen = strlen(thisGname);
     if (lastGname == NULL || thisGnameLen != lastGnameLen ||
 	strcmp(thisGname, lastGname) != 0)
@@ -90,25 +150,34 @@ static char * lastGname = NULL;
 	}
 	strcpy(lastGname, thisGname);
 
-	grent = getgrnam(thisGname);
-	if (grent == NULL) {
-	    /* FIX: shrug */
-	    endgrent();
+	if (safe) {
+	    int gid = safe_lookup("/etc/group", thisGname);
+	    if (gid < 0)
+		return -1;
+	    lastGid = (gid_t)gid;
+	} else {
 	    grent = getgrnam(thisGname);
 	    if (grent == NULL) {
-		/* XXX The filesystem package needs group/lock w/o getgrnam. */
-		if (strcmp(thisGname, "lock") == 0) {
-		    *gid = lastGid = 54;
-		    return 0;
-		} else
-		if (strcmp(thisGname, "mail") == 0) {
-		    *gid = lastGid = 12;
-		    return 0;
-		} else
-		return -1;
+		/* FIX: shrug */
+		endgrent();
+		grent = getgrnam(thisGname);
+		if (grent == NULL) {
+#ifdef STRANGE_FEDORA_HACKS
+		    /* XXX The filesystem package needs group/lock w/o getgrnam. */
+		    if (strcmp(thisGname, "lock") == 0) {
+			*gid = lastGid = 54;
+			return 0;
+		    } else
+		    if (strcmp(thisGname, "mail") == 0) {
+			*gid = lastGid = 12;
+			return 0;
+		    } else
+#endif
+		    return -1;
+		}
 	    }
+	    lastGid = grent->gr_gid;
 	}
-	lastGid = grent->gr_gid;
     }
 
     *gid = lastGid;
@@ -116,6 +185,12 @@ static char * lastGname = NULL;
     return 0;
 }
 
+int gnameToGid(const char * thisGname, gid_t * gid)
+{
+    return gnameToGid_safe(thisGname, gid, 0);
+}
+
+
 const char * uidToUname(uid_t uid)
 {
     static uid_t lastUid = (uid_t) -1;