summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Brockschmidt <he@debian.org>2008-07-28 16:09:53 -0400
committerColin Walters <walters@verbum.org>2008-07-28 16:14:18 -0400
commit9d51f086b05df196b94234d6a0d388594feedd73 (patch)
tree7dab91cd2603b1f6a67febdeb7e0433bc86fa034
parent121c6b13a35759ee590551cfb9978e9f20766a12 (diff)
Bug 16727: Handle ERANGE for getgr; fixes user in many groups
Patch originally from Noèl Köthe. Modified by Colin Walters <walters@verbum.org> * 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.
-rw-r--r--dbus/dbus-sysdeps-unix.c65
-rw-r--r--dbus/dbus-sysdeps-util-unix.c58
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;
}
}