From 52e8a5ec2bd1cda9beab790b050e6af8a245250e Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Sun, 26 Jan 2014 15:24:55 +0100 Subject: [PATCH] Red Hat issue 1021429: getgroupent fails with large number of groups --- CHANGES | 4 ++++ README | 5 +++++ config.h.in | 3 ++- configure.in | 2 ++ sycls.c | 24 ++++++++++++++++++++++-- sycls.h | 4 +++- sysutils.c | 43 +++++++++++++++++++++++++++++++++++++++---- sysutils.h | 4 ++-- xio-process.c | 4 ++-- xio-process.h | 4 ++-- 10 files changed, 83 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index f7c9fb5..03d1cb5 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/README b/README index 2bd0d54..ae8e289 100644 --- a/README +++ b/README @@ -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: diff --git a/config.h.in b/config.h.in index aff0ddf..f03ed3a 100644 --- a/config.h.in +++ b/config.h.in @@ -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 diff --git a/configure.in b/configure.in index b39862e..c94397f 100644 --- a/configure.in +++ b/configure.in @@ -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]) diff --git a/sycls.c b/sycls.c index 68729ea..3ba0b39 100644 --- a/sycls.c +++ b/sycls.c @@ -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); diff --git a/sycls.h b/sycls.h index 5715e6b..1378071 100644 --- a/sycls.h +++ b/sycls.h @@ -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) diff --git a/sysutils.c b/sysutils.c index 21215c6..fb39d1a 100644 --- a/sysutils.c +++ b/sysutils.c @@ -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 diff --git a/sysutils.h b/sysutils.h index f55f676..fda3175 100644 --- a/sysutils.h +++ b/sysutils.h @@ -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 diff --git a/xio-process.c b/xio-process.c index 96d93dc..d76fac2 100644 --- a/xio-process.c +++ b/xio-process.c @@ -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 */ diff --git a/xio-process.h b/xio-process.h index d67594c..7a6815f 100644 --- a/xio-process.h +++ b/xio-process.h @@ -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 */