rpm/safeugid.diff

237 lines
6.2 KiB
Diff

--- 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;