Red Hat issue 1021429: getgroupent fails with large number of groups

This commit is contained in:
Gerhard Rieger 2014-01-26 15:24:55 +01:00
parent ab74be65e5
commit 52e8a5ec2b
10 changed files with 83 additions and 14 deletions

View file

@ -58,6 +58,10 @@ porting:
Adapted, improved test.sh script
Red Hat issue 1021429: getgroupent fails with large number of groups;
use getgrouplist() when available instead of sequence of calls to
getgrent()
docu:
libwrap always logs to syslog

5
README
View file

@ -132,6 +132,11 @@ the file PORTING.
platform specifics - redhat
---------------------------
Install the following packages before building socat:
tcp_wrappers-devel
readline-devel
openssl-devel
On RedHat Linux 9.0, including openssl/ssl.h might fail due to problems with
the krb5-devel package. configure reacts with disabling openssl integration.
To solve this issue, help cpp to find the krb5.h include file:

View file

@ -1,5 +1,5 @@
/* source: config.h.in */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __config_h_included
@ -498,6 +498,7 @@
#undef HAVE_SETGRENT
#undef HAVE_GETGRENT
#undef HAVE_ENDGRENT
#undef HAVE_GETGROUPLIST
#undef WITH_HELP
#undef WITH_STDIO

View file

@ -82,6 +82,8 @@ AC_CHECK_HEADERS(linux/fs.h linux/ext2_fs.h)
dnl Checks for setgrent, getgrent and endgrent.
AC_CHECK_FUNCS(setgrent getgrent endgrent)
dnl Checks for getgrouplist() /* BSD */
AC_CHECK_FUNCS(getgrouplist)
dnl Link libresolv if necessary (for Mac OS X)
AC_SEARCH_LIBS([res_9_init], [resolv])

24
sycls.c
View file

@ -1,5 +1,5 @@
/* source: sycls.c */
/* Copyright Gerhard Rieger 2001-2009 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* explicit system call and C library trace function, for those who miss strace
@ -276,7 +276,12 @@ int Getgroups(int size, gid_t list[]) {
#if HAVE_SETGROUPS
int Setgroups(size_t size, const gid_t *list) {
int result, _errno;
Debug2("setgroups("F_Zu", "F_gid",...)", size, list[0]);
switch (size) {
case 0: Debug1("setgroups("F_Zu", [])", size); break;;
case 1: Debug2("setgroups("F_Zu", ["F_gid"])", size, list[0]); break;;
case 2: Debug3("setgroups("F_Zu", ["F_gid","F_gid"])", size, list[0], list[1]); break;;
default: Debug3("setgroups("F_Zu", ["F_gid","F_gid",...])", size, list[0], list[1]); break;;
}
result = setgroups(size, list);
_errno = errno;
Debug1("setgroups() -> %d", result);
@ -285,6 +290,21 @@ int Setgroups(size_t size, const gid_t *list) {
}
#endif
#if HAVE_GETGROUPLIST
int Getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) {
int n = *ngroups, result;
Debug4("getgrouplist(\"%s\", "F_gid", %p, [%d])", user, group, groups, n);
result = getgrouplist(user, group, groups, ngroups);
switch (Min(n,*ngroups)) {
case 0: Debug2("getgrouplist(,, [], [%d]) -> %d", *ngroups, result); break;
case 1: Debug3("getgrouplist(,, ["F_gid"], [%d]) -> %d", groups[0], *ngroups, result); break;
case 2: Debug4("getgrouplist(,, ["F_gid","F_gid"], [%d]) -> %d", groups[0], groups[1], *ngroups, result); break;
default: Debug4("getgrouplist(,, ["F_gid","F_gid",...], [%d]) -> %d", groups[0], groups[1], *ngroups, result); break;
}
return result;
}
#endif
int Chdir(const char *path) {
int result, _errno;
Debug1("chdir(\"%s\")", path);

View file

@ -1,5 +1,5 @@
/* source: sycls.h */
/* Copyright Gerhard Rieger 2001-2008 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sycls_h_included
@ -37,6 +37,7 @@ int Setgid(gid_t gid);
int Initgroups(const char *user, gid_t group);
int Getgroups(int size, gid_t list[]);
int Setgroups(size_t size, const gid_t *list);
int Getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups);
int Chdir(const char *path);
int Chroot(const char *path);
int Gettimeofday(struct timeval *tv, struct timezone *tz);
@ -175,6 +176,7 @@ void Add_history(const char *string);
#define Initgroups(u,g) initgroups(u,g)
#define Getgroups(s,l) getgroups(s,l)
#define Setgroups(s,l) setgroups(s,l)
#define Getgrouplist(u,g,gs,n) getgrouplist(u,g,gs,n)
#define Chdir(p) chdir(p)
#define Chroot(p) chroot(p)
#define Gettimeofday(tv,tz) gettimeofday(tv,tz)

View file

@ -413,15 +413,49 @@ char *sockaddr_inet6_info(const struct sockaddr_in6 *sa, char *buff, size_t blen
}
#endif /* WITH_IP6 */
#if defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
/* fill the list with the supplementary group ids of user.
#if HAVE_GETGROUPLIST || (defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT))
/* fills the list with the supplementary group ids of user.
caller passes size of list in ngroups, function returns number of groups in
ngroups.
function returns 0 if 0 or more groups were found, or 1 if the list is too
short. */
int getusergroups(const char *user, gid_t *list, size_t *ngroups) {
int getusergroups(const char *user, gid_t *list, int *ngroups) {
#if HAVE_GETGROUPLIST
/* we prefer getgrouplist because it may be much faster with many groups, but it is not standard */
gid_t grp, twogrps[2];
int two = 2;
/* getgrouplist requires to pass an extra group id, typically the users primary group, that is then added to the supplementary group list. We don't want such an additional group in the result, but there is not "unspecified" gid value available. Thus we try to find an abitrary supplementary group id that we then pass in a second call to getgrouplist. */
grp = 0;
Getgrouplist(user, grp, twogrps, &two);
if (two == 1) {
/* either user has just this supp group, or none; we try another id */
grp = 1; two = 2;
Getgrouplist(user, grp, twogrps, &two);
if (two == 1) {
/* user has no supp group */
*ngroups = 0;
return 0;
}
/* user has just the first tried group */
*ngroups = 1; list[0] = grp;
return 0;
}
/* find the first supp group that is not our grp, and use its id */
if (twogrps[0] == grp) {
grp = twogrps[1];
} else {
grp = twogrps[0];
}
if (Getgrouplist(user, grp, list, ngroups) < 0) {
return 1;
}
return 0;
#elif defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
/* this is standard (POSIX) but may be slow */
struct group *grp;
size_t i = 0;
int i = 0;
setgrent();
while (grp = getgrent()) {
@ -439,6 +473,7 @@ int getusergroups(const char *user, gid_t *list, size_t *ngroups) {
endgrent();
*ngroups = i;
return 0;
#endif /* HAVE_SETGRENT... */
}
#endif

View file

@ -1,5 +1,5 @@
/* source: sysutils.h */
/* Copyright Gerhard Rieger 2001-2011 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysutils_h_included
@ -74,7 +74,7 @@ extern const char *inet_ntop(int pf, const void *binaddr,
#endif
#if defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT)
extern int getusergroups(const char *user, gid_t *list, size_t *ngroups);
extern int getusergroups(const char *user, gid_t *list, int *ngroups);
#endif
#if !HAVE_HSTRERROR

View file

@ -1,5 +1,5 @@
/* source: xio-process.c */
/* Copyright Gerhard Rieger 2001-2009 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
/* this file handles process related addresses options */
@ -30,7 +30,7 @@ bool delayeduser = false;
uid_t delayeduser_uid; /* numeric user id to switch to */
gid_t delayeduser_gid; /* numeric group id to switch to */
gid_t delayeduser_gids[NGROUPS]; /* num.supplementary group ids */
size_t delayeduser_ngids; /* number of suppl. gids */
int delayeduser_ngids; /* number of suppl. gids */
char *delayeduser_name; /* name of user to switch to */
char *delayeduser_dir; /* home directory of user to switch to */
char *delayeduser_shell; /* login shell of user to switch to */

View file

@ -1,5 +1,5 @@
/* source: xio-process.h */
/* Copyright Gerhard Rieger 2001-2009 */
/* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_process_h_included
@ -24,7 +24,7 @@ extern bool delayeduser;
extern uid_t delayeduser_uid; /* numeric user id to switch to */
extern gid_t delayeduser_gid; /* numeric group id to switch to */
extern gid_t delayeduser_gids[NGROUPS]; /* num.supplementary group ids */
extern size_t delayeduser_ngids; /* number of suppl. gids */
extern int delayeduser_ngids; /* number of suppl. gids */
extern char *delayeduser_name; /* name of user to switch to */
extern char *delayeduser_dir; /* home directory of user to switch to */
extern char *delayeduser_shell; /* login shell of user to switch to */