--- lib/fsm.c.orig 2010-03-26 15:06:20.000000000 +0000 +++ lib/fsm.c 2010-03-26 15:16:31.000000000 +0000 @@ -736,22 +736,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); @@ -773,8 +777,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-12-07 14:36:49.000000000 +0000 +++ lib/misc.c 2010-03-26 15:26:05.000000000 +0000 @@ -14,6 +14,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 @@ -21,11 +57,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; @@ -38,6 +75,11 @@ static char * lastUname = NULL; return 0; } + if (safe != lastUnameSafe) { + lastUnameLen = 0; + lastUnameSafe = safe; + } + thisUnameLen = strlen(thisUname); if (lastUname == NULL || thisUnameLen != lastUnameLen || !rstreq(thisUname, lastUname)) @@ -48,15 +90,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; @@ -64,11 +112,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; @@ -81,6 +136,11 @@ static char * lastGname = NULL; return 0; } + if (safe != lastGnameSafe) { + lastGnameLen = 0; + lastGnameSafe = safe; + } + thisGnameLen = strlen(thisGname); if (lastGname == NULL || thisGnameLen != lastGnameLen || !rstreq(thisGname, lastGname)) @@ -91,25 +151,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 (rstreq(thisGname, "lock")) { - *gid = lastGid = 54; - return 0; - } else - if (rstreq(thisGname, "mail")) { - *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 (rstreq(thisGname, "lock")) { + *gid = lastGid = 54; + return 0; + } else + if (rstreq(thisGname, "mail")) { + *gid = lastGid = 12; + return 0; + } else +#endif + return -1; + } } + lastGid = grent->gr_gid; } - lastGid = grent->gr_gid; } *gid = lastGid; @@ -117,6 +186,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;