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

This commit is contained in:
Gerhard Rieger 2014-03-26 14:38:23 +01:00
parent d123461127
commit 1d8b6bbb9b
10 changed files with 82 additions and 13 deletions

View file

@ -148,6 +148,10 @@ porting:
Adapted, improved test.sh script 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()
libwrap always logs to syslog libwrap always logs to syslog
added actual text version of GPLv2 added actual text version of GPLv2

5
README
View file

@ -132,6 +132,11 @@ the file PORTING.
platform specifics - redhat 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 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. the krb5-devel package. configure reacts with disabling openssl integration.
To solve this issue, help cpp to find the krb5.h include file: To solve this issue, help cpp to find the krb5.h include file:

View file

@ -498,6 +498,7 @@
#undef HAVE_SETGRENT #undef HAVE_SETGRENT
#undef HAVE_GETGRENT #undef HAVE_GETGRENT
#undef HAVE_ENDGRENT #undef HAVE_ENDGRENT
#undef HAVE_GETGROUPLIST
#undef WITH_HELP #undef WITH_HELP
#undef WITH_NOP #undef WITH_NOP

View file

@ -82,6 +82,8 @@ AC_CHECK_HEADERS(linux/fs.h linux/ext2_fs.h)
dnl Checks for setgrent, getgrent and endgrent. dnl Checks for setgrent, getgrent and endgrent.
AC_CHECK_FUNCS(setgrent getgrent 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) dnl Link libresolv if necessary (for Mac OS X)
AC_SEARCH_LIBS([res_9_init], [resolv]) AC_SEARCH_LIBS([res_9_init], [resolv])

24
sycls.c
View file

@ -1,5 +1,5 @@
/* source: sycls.c */ /* source: sycls.c */
/* Copyright Gerhard Rieger 2001-2012 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* 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 /* 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 #if HAVE_SETGROUPS
int Setgroups(size_t size, const gid_t *list) { int Setgroups(size_t size, const gid_t *list) {
int result, _errno; 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); result = setgroups(size, list);
_errno = errno; _errno = errno;
Debug1("setgroups() -> %d", result); Debug1("setgroups() -> %d", result);
@ -285,6 +290,21 @@ int Setgroups(size_t size, const gid_t *list) {
} }
#endif #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 Chdir(const char *path) {
int result, _errno; int result, _errno;
Debug1("chdir(\"%s\")", path); Debug1("chdir(\"%s\")", path);

View file

@ -1,5 +1,5 @@
/* source: sycls.h */ /* source: sycls.h */
/* Copyright Gerhard Rieger 2001-2008 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sycls_h_included #ifndef __sycls_h_included
@ -37,6 +37,7 @@ int Setgid(gid_t gid);
int Initgroups(const char *user, gid_t group); int Initgroups(const char *user, gid_t group);
int Getgroups(int size, gid_t list[]); int Getgroups(int size, gid_t list[]);
int Setgroups(size_t size, const 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 Chdir(const char *path);
int Chroot(const char *path); int Chroot(const char *path);
int Gettimeofday(struct timeval *tv, struct timezone *tz); int Gettimeofday(struct timeval *tv, struct timezone *tz);
@ -187,6 +188,7 @@ int Gzclose(gzFile file) {
#define Initgroups(u,g) initgroups(u,g) #define Initgroups(u,g) initgroups(u,g)
#define Getgroups(s,l) getgroups(s,l) #define Getgroups(s,l) getgroups(s,l)
#define Setgroups(s,l) setgroups(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 Chdir(p) chdir(p)
#define Chroot(p) chroot(p) #define Chroot(p) chroot(p)
#define Gettimeofday(tv,tz) gettimeofday(tv,tz) #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 */ #endif /* WITH_IP6 */
#if defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT) #if HAVE_GETGROUPLIST || (defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT))
/* fill the list with the supplementary group ids of user. /* fills the list with the supplementary group ids of user.
caller passes size of list in ngroups, function returns number of groups in caller passes size of list in ngroups, function returns number of groups in
ngroups. ngroups.
function returns 0 if 0 or more groups were found, or 1 if the list is too function returns 0 if 0 or more groups were found, or 1 if the list is too
short. */ 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; struct group *grp;
size_t i = 0; int i = 0;
setgrent(); setgrent();
while (grp = getgrent()) { while (grp = getgrent()) {
@ -439,6 +473,7 @@ int getusergroups(const char *user, gid_t *list, size_t *ngroups) {
endgrent(); endgrent();
*ngroups = i; *ngroups = i;
return 0; return 0;
#endif /* HAVE_SETGRENT... */
} }
#endif #endif

View file

@ -1,5 +1,5 @@
/* source: sysutils.h */ /* source: sysutils.h */
/* Copyright Gerhard Rieger 2001-2012 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __sysutils_h_included #ifndef __sysutils_h_included
@ -75,7 +75,7 @@ extern const char *inet_ntop(int pf, const void *binaddr,
#endif #endif
#if defined(HAVE_SETGRENT) && defined(HAVE_GETGRENT) && defined(HAVE_ENDGRENT) #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 #endif
#if !HAVE_HSTRERROR #if !HAVE_HSTRERROR

View file

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

View file

@ -1,5 +1,5 @@
/* source: xio-process.h */ /* source: xio-process.h */
/* Copyright Gerhard Rieger 2001-2012 */ /* Copyright Gerhard Rieger */
/* Published under the GNU General Public License V.2, see file COPYING */ /* Published under the GNU General Public License V.2, see file COPYING */
#ifndef __xio_process_h_included #ifndef __xio_process_h_included
@ -24,7 +24,7 @@ extern bool delayeduser;
extern uid_t delayeduser_uid; /* numeric user id to switch to */ 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_gid; /* numeric group id to switch to */
extern gid_t delayeduser_gids[NGROUPS]; /* num.supplementary group ids */ 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_name; /* name of user to switch to */
extern char *delayeduser_dir; /* home directory 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 */ extern char *delayeduser_shell; /* login shell of user to switch to */