File safeugid.diff of Package rpm

--- lib/fsm.c.orig	2010-03-11 16:16:48.000000000 +0000
+++ lib/fsm.c	2010-03-11 17:00:46.000000000 +0000
@@ -760,14 +760,18 @@ int fsmMapAttrs(FSM_t fsm)
     int i = fsm->ix;
 
     if (fi && i >= 0 && i < fi->fc) {
+	rpmts ts = fsmGetTs(fsm);
 	mode_t perms = (S_ISDIR(st->st_mode) ? fi->dperms : fi->fperms);
 	mode_t finalMode = (fi->fmodes ? fi->fmodes[i] : perms);
 	dev_t finalRdev = (fi->frdevs ? fi->frdevs[i] : 0);
 	int_32 finalMtime = (fi->fmtimes ? fi->fmtimes[i] : 0);
+	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 = fi->uid;
 	gid_t gid = fi->gid;
 
-	if (fi->fuser && unameToUid(fi->fuser[i], &uid)) {
+	if (fi->fuser && unameToUid_safe(fi->fuser[i], &uid, safe)) {
 	    if (fsm->goal == FSM_PKGINSTALL)
 		rpmMessage(RPMMESS_WARNING,
 		    _("user %s does not exist - using root\n"), fi->fuser[i]);
@@ -775,7 +779,7 @@ int fsmMapAttrs(FSM_t fsm)
 	    finalMode &= ~S_ISUID;      /* turn off suid bit */
 	}
 
-	if (fi->fgroup && gnameToGid(fi->fgroup[i], &gid)) {
+	if (fi->fgroup && gnameToGid_safe(fi->fgroup[i], &gid, safe)) {
 	    if (fsm->goal == FSM_PKGINSTALL)
 		rpmMessage(RPMMESS_WARNING,
 		    _("group %s does not exist - using root\n"), fi->fgroup[i]);
@@ -798,8 +802,7 @@ int fsmMapAttrs(FSM_t fsm)
 	if (fsm->mapFlags & CPIO_MAP_GID)
 	    st->st_gid = gid;
 
-	{   rpmts ts = fsmGetTs(fsm);
-
+	{
 	    /*
 	     * Set file md5 (if not disabled).
 	     */
--- rpmio/ugid.c.orig	2010-03-11 15:40:31.000000000 +0000
+++ rpmio/ugid.c	2010-03-11 17:49:09.000000000 +0000
@@ -6,6 +6,37 @@
 #include "ugid.h"
 #include "debug.h"
 
+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
@@ -13,11 +44,12 @@
    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)
 {
 /*@only@*/ 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;
@@ -31,6 +63,10 @@ int unameToUid(const char * thisUname, u
 /*@=boundswrite@*/
 	return 0;
     }
+    if (safe != lastUnameSafe) {
+	lastUnameLen = 0;
+	lastUnameSafe = safe;
+    }
 
     thisUnameLen = strlen(thisUname);
     if (lastUname == NULL || thisUnameLen != lastUnameLen ||
@@ -44,16 +80,23 @@ int unameToUid(const char * thisUname, u
 	strcpy(lastUname, thisUname);
 /*@=boundswrite@*/
 
-	pwent = getpwnam(thisUname);
-	if (pwent == NULL) {
-	    /*@-internalglobs@*/ /* FIX: shrug */
-	    endpwent();
-	    /*@=internalglobs@*/
+	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) {
+		/*@-internalglobs@*/ /* FIX: shrug */
+		endpwent();
+		/*@=internalglobs@*/
+		pwent = getpwnam(thisUname);
+		if (pwent == NULL) return -1;
+	    }
 
-	lastUid = pwent->pw_uid;
+	    lastUid = pwent->pw_uid;
+	}
     }
 
 /*@-boundswrite@*/
@@ -63,11 +106,17 @@ int unameToUid(const char * thisUname, u
     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)
 {
 /*@only@*/ 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;
@@ -81,6 +130,10 @@ int gnameToGid(const char * thisGname, g
 /*@=boundswrite@*/
 	return 0;
     }
+    if (safe != lastGnameSafe) {
+	lastGnameLen = 0;
+	lastGnameSafe = safe;
+    }
 
     thisGnameLen = strlen(thisGname);
     if (lastGname == NULL || thisGnameLen != lastGnameLen ||
@@ -94,30 +147,39 @@ int gnameToGid(const char * thisGname, g
 	strcpy(lastGname, thisGname);
 /*@=boundswrite@*/
 
-	grent = getgrnam(thisGname);
-	if (grent == NULL) {
-	    /*@-internalglobs@*/ /* FIX: shrug */
-	    endgrent();
-	    /*@=internalglobs@*/
+	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) {
-/*@-boundswrite@*/
-		    *gid = lastGid = 54;
-/*@=boundswrite@*/
-		    return 0;
-		} else
-		if (strcmp(thisGname, "mail") == 0) {
-/*@-boundswrite@*/
-		    *gid = lastGid = 12;
-/*@=boundswrite@*/
-		    return 0;
-		} else
-		return -1;
+		/*@-internalglobs@*/ /* FIX: shrug */
+		endgrent();
+		/*@=internalglobs@*/
+		grent = getgrnam(thisGname);
+		if (grent == NULL) {
+#if 0
+		    /* XXX The filesystem package needs group/lock w/o getgrnam. */
+		    if (strcmp(thisGname, "lock") == 0) {
+    /*@-boundswrite@*/
+			*gid = lastGid = 54;
+    /*@=boundswrite@*/
+			return 0;
+		    } else
+		    if (strcmp(thisGname, "mail") == 0) {
+    /*@-boundswrite@*/
+			*gid = lastGid = 12;
+    /*@=boundswrite@*/
+			return 0;
+		    } else
+#endif
+		    return -1;
+		}
 	    }
+	    lastGid = grent->gr_gid;
 	}
-	lastGid = grent->gr_gid;
     }
 
 /*@-boundswrite@*/
@@ -127,6 +189,11 @@ int gnameToGid(const char * thisGname, g
     return 0;
 }
 
+int gnameToGid(const char * thisGname, gid_t * gid)
+{
+    return gnameToGid_safe(thisGname, gid, 0);
+}
+
 char * uidToUname(uid_t uid)
 {
     static uid_t lastUid = (uid_t) -1;