Hi folks, we had lots of trouble with rpm's user and group handling in our kiwi system (which creates bootable ISOs). kiwi uses rpm --root to install the selected rpms into a directory, somehow we sometimes got wrong userids and groupids for files.
It turns out the glibc and nscd are to blame. There seems to be no way to tell glibc to stop using nscd if it created a connection for some lookup. rpm always does lookups on startup, it has to get the home directory of the caller for example. Even if nscd is not started glibc's nss functions also cache their setting, so if you use some exotic nss module for authentification, it'll still be used after the chroot(). At some point I basically gave up and wrote the attached patch. It changes rpmugUid/rpmugGid to do the lookup itself if a chroot() was done. I know it is a bit of a hack, but I have not found another way. The patch also - fixes the cache usage. lastUnameLen/lastGnameLen were never set, so the code *always* did a getpwuid/gid call! - renames lastU/GnameLen to lastU/GnameAlloced in rpmugU/Gname, so that it is consistent with the rpmugU/Gid function. Even if you do not want the safe_lookup() part, having a rpmugChroot() function that calls endpwent()/endgrent() and drops the local caches if a chroot is done seems like a good idea. Cheers, Michael. -- Michael Schroeder m...@suse.de SUSE LINUX Products GmbH, GF Jeff Hawn, HRB 16746 AG Nuernberg main(_){while(_=~getchar())putchar(~_-1/(~(_|32)/13*2-11)*13);}
--- ./lib/rpmchroot.c.orig 2011-05-12 08:26:10.000000000 +0000 +++ ./lib/rpmchroot.c 2011-05-12 08:28:32.000000000 +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 2011-05-12 08:13:52.000000000 +0000 +++ ./lib/rpmug.c 2011-05-12 08:33:28.000000000 +0000 @@ -35,6 +35,47 @@ const char * rpmugStashStr(const char *s return ret; } +#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 @@ -68,17 +109,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; @@ -111,18 +163,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; @@ -134,7 +197,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; @@ -151,9 +214,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); @@ -165,7 +228,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; @@ -182,9 +245,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); @@ -200,3 +263,16 @@ void rpmugFree(void) rpmugGname(-1); strStash = strCacheFree(strStash); } + +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 2011-05-12 08:13:52.000000000 +0000 +++ ./lib/rpmug.h 2011-05-12 08:26:56.000000000 +0000 @@ -15,4 +15,6 @@ const char * rpmugGname(gid_t gid); void rpmugFree(void); +void rpmugChroot(int in); + #endif /* _RPMUG_H */
_______________________________________________ Rpm-maint mailing list Rpm-maint@lists.rpm.org http://lists.rpm.org/mailman/listinfo/rpm-maint