From 9d51f086b05df196b94234d6a0d388594feedd73 Mon Sep 17 00:00:00 2001 From: Marc Brockschmidt Date: Mon, 28 Jul 2008 16:09:53 -0400 Subject: Bug 16727: Handle ERANGE for getgr; fixes user in many groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch originally from Noèl Köthe. Modified by Colin Walters * dbus/dbus-sysdeps-unix.c, dbus/dbus-sysdeps-unix-utils.c: Use a while() loop to reallocate buffer if we get ERANGE return. This fixes the case where a user is in a large number of groups. --- dbus/dbus-sysdeps-unix.c | 65 +++++++++++++++++++++++++++++++++---------- dbus/dbus-sysdeps-util-unix.c | 58 ++++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 27 deletions(-) diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 64d925d9..c96499a6 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -1487,28 +1487,60 @@ fill_user_info (DBusUserInfo *info, { struct passwd *p; int result; - char buf[1024]; + size_t buflen; + char *buf; struct passwd p_str; - p = NULL; + /* retrieve maximum needed size for buf */ + buflen = sysconf (_SC_GETPW_R_SIZE_MAX); + + if (buflen <= 0) + buflen = 1024; + + result = -1; + while (1) + { + buf = dbus_malloc (buflen); + if (buf == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + p = NULL; #ifdef HAVE_POSIX_GETPWNAM_R - if (uid != DBUS_UID_UNSET) - result = getpwuid_r (uid, &p_str, buf, sizeof (buf), - &p); - else - result = getpwnam_r (username_c, &p_str, buf, sizeof (buf), - &p); + if (uid != DBUS_UID_UNSET) + result = getpwuid_r (uid, &p_str, buf, buflen, + &p); + else + result = getpwnam_r (username_c, &p_str, buf, buflen, + &p); #else - if (uid != DBUS_UID_UNSET) - p = getpwuid_r (uid, &p_str, buf, sizeof (buf)); - else - p = getpwnam_r (username_c, &p_str, buf, sizeof (buf)); - result = 0; + if (uid != DBUS_UID_UNSET) + p = getpwuid_r (uid, &p_str, buf, buflen); + else + p = getpwnam_r (username_c, &p_str, buf, buflen); + result = 0; #endif /* !HAVE_POSIX_GETPWNAM_R */ + //Try a bigger buffer if ERANGE was returned + if (result == ERANGE && buflen < 512 * 1024) + { + dbus_free (buf); + buflen *= 2; + } + else + { + break; + } + } if (result == 0 && p == &p_str) { if (!fill_user_info_from_passwd (p, info, error)) - return FALSE; + { + dbus_free (buf); + return FALSE; + } + dbus_free (buf); } else { @@ -1516,6 +1548,7 @@ fill_user_info (DBusUserInfo *info, "User \"%s\" unknown or no memory to allocate password entry\n", username_c ? username_c : "???"); _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???"); + dbus_free (buf); return FALSE; } } @@ -1532,7 +1565,9 @@ fill_user_info (DBusUserInfo *info, if (p != NULL) { if (!fill_user_info_from_passwd (p, info, error)) - return FALSE; + { + return FALSE; + } } else { diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index 9ff3fbc1..55eb9346 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -828,31 +828,65 @@ fill_group_info (DBusGroupInfo *info, { struct group *g; int result; - char buf[1024]; + size_t buflen; + char *buf; struct group g_str; + dbus_bool_t b; - g = NULL; -#ifdef HAVE_POSIX_GETPWNAM_R + /* retrieve maximum needed size for buf */ + buflen = sysconf (_SC_GETGR_R_SIZE_MAX); - if (group_c_str) - result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf), - &g); - else - result = getgrgid_r (gid, &g_str, buf, sizeof (buf), - &g); + if (buflen <= 0) + buflen = 1024; + + result = -1; + while (1) + { + buf = dbus_malloc (buflen); + if (buf == NULL) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); + return FALSE; + } + + g = NULL; +#ifdef HAVE_POSIX_GETPWNAM_R + if (group_c_str) + result = getgrnam_r (group_c_str, &g_str, buf, buflen, + &g); + else + result = getgrgid_r (gid, &g_str, buf, buflen, + &g); #else - g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf)); - result = 0; + g = getgrnam_r (group_c_str, &g_str, buf, buflen); + result = 0; #endif /* !HAVE_POSIX_GETPWNAM_R */ + /* Try a bigger buffer if ERANGE was returned: + https://bugs.freedesktop.org/show_bug.cgi?id=16727 + */ + if (result == ERANGE && buflen < 512 * 1024) + { + dbus_free (buf); + buflen *= 2; + } + else + { + break; + } + } + if (result == 0 && g == &g_str) { - return fill_user_info_from_group (g, info, error); + b = fill_user_info_from_group (g, info, error); + dbus_free (buf); + return b; } else { dbus_set_error (error, _dbus_error_from_errno (errno), "Group %s unknown or failed to look it up\n", group_c_str ? group_c_str : "???"); + dbus_free (buf); return FALSE; } } -- cgit