diff -pruN glibc-2.12-2-gc4ccff1/nis/nss_compat/compat-initgroups.c glibc-2.12-2-gc4ccff1.patched/nis/nss_compat/compat-initgroups.c --- glibc-2.12-2-gc4ccff1/nis/nss_compat/compat-initgroups.c 2010-05-04 16:57:23.000000000 +0530 +++ glibc-2.12-2-gc4ccff1.patched/nis/nss_compat/compat-initgroups.c 2012-02-21 11:11:19.877008465 +0530 @@ -297,6 +297,8 @@ getgrent_next_nss (ent_t *ent, char *buf if (nss_initgroups_dyn (user, group, &mystart, &mysize, &mygroups, limit, errnop) == NSS_STATUS_SUCCESS) { + status = NSS_STATUS_NOTFOUND; + /* If there is no blacklist we can trust the underlying initgroups implementation. */ if (ent->blacklist.current <= 1) @@ -309,6 +311,7 @@ getgrent_next_nss (ent_t *ent, char *buf overwrite the pointer with one to a bigger buffer. */ char *tmpbuf = buffer; size_t tmplen = buflen; + bool use_malloc = false; for (int i = 0; i < mystart; i++) { @@ -316,21 +319,36 @@ getgrent_next_nss (ent_t *ent, char *buf tmpbuf, tmplen, errnop)) == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) - if (tmpbuf == buffer) - { - tmplen *= 2; - tmpbuf = __alloca (tmplen); - } - else - tmpbuf = extend_alloca (tmpbuf, tmplen, 2 * tmplen); + { + if (__libc_use_alloca (tmplen * 2)) + { + if (tmpbuf == buffer) + { + tmplen *= 2; + tmpbuf = __alloca (tmplen); + } + else + tmpbuf = extend_alloca (tmpbuf, tmplen, tmplen * 2); + } + else + { + tmplen *= 2; + char *newbuf = realloc (use_malloc ? tmpbuf : NULL, tmplen); + + if (newbuf == NULL) + { + status = NSS_STATUS_TRYAGAIN; + goto done; + } + use_malloc = true; + tmpbuf = newbuf; + } + } if (__builtin_expect (status != NSS_STATUS_NOTFOUND, 1)) { if (__builtin_expect (status != NSS_STATUS_SUCCESS, 0)) - { - free (mygroups); - return status; - } + goto done; if (!in_blacklist (grpbuf.gr_name, strlen (grpbuf.gr_name), ent) @@ -348,11 +366,17 @@ getgrent_next_nss (ent_t *ent, char *buf } } } + + status = NSS_STATUS_NOTFOUND; + + done: + if (use_malloc) + free (tmpbuf); } free (mygroups); - return NSS_STATUS_NOTFOUND; + return status; } free (mygroups); @@ -506,6 +530,7 @@ _nss_compat_initgroups_dyn (const char * char *tmpbuf; enum nss_status status; ent_t intern = { true, false, false, NULL, {NULL, 0, 0} }; + bool use_malloc = false; status = internal_setgrent (&intern); if (status != NSS_STATUS_SUCCESS) @@ -519,13 +544,32 @@ _nss_compat_initgroups_dyn (const char * user, group, start, size, groupsp, limit, errnop)) == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) - tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); + if (__libc_use_alloca (buflen * 2)) + tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); + else + { + buflen *= 2; + char *newbuf = realloc (use_malloc ? tmpbuf : NULL, buflen); + if (newbuf == NULL) + { + status = NSS_STATUS_TRYAGAIN; + goto done; + } + use_malloc = true; + tmpbuf = newbuf; + } } while (status == NSS_STATUS_SUCCESS); + status = NSS_STATUS_SUCCESS; + + done: + if (use_malloc) + free (tmpbuf); + internal_endgrent (&intern); - return NSS_STATUS_SUCCESS; + return status; }