capabilities: Handle ERANGE in user and group lookups

As it turns out, getpwnam_r, getgrnam_r, and friends will return
ERANGE if _any_ user or group on the system is larger than will fit
into the scratch buffer you pass to them.

This reworks the resolve_uid and resolve_gid methods plus
init_supplementary_groups to use a variable-size buffer that is grown
until the results fit.

Based on a patch by Evan Broder.

Closes strongswan/strongswan#12.
This commit is contained in:
Tobias Brunner
2015-06-23 10:03:38 +02:00
parent 5fbc709224
commit b01b331afe
+48 -12
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2013 Tobias Brunner * Copyright (C) 2012-2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* Copyright (C) 2012 Martin Willi * Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG * Copyright (C) 2012 revosec AG
@@ -288,13 +288,25 @@ METHOD(capabilities_t, resolve_uid, bool,
#ifdef HAVE_GETPWNAM_R #ifdef HAVE_GETPWNAM_R
struct passwd passwd; struct passwd passwd;
char buf[1024]; size_t buflen = 1024;
char *buf = NULL;
err = getpwnam_r(username, &passwd, buf, sizeof(buf), &pwp); while (TRUE)
if (pwp)
{ {
this->uid = pwp->pw_uid; buf = realloc(buf, buflen);
err = getpwnam_r(username, &passwd, buf, buflen, &pwp);
if (err == ERANGE)
{
buflen *= 2;
continue;
}
if (pwp)
{
this->uid = pwp->pw_uid;
}
break;
} }
free(buf);
#else /* HAVE GETPWNAM_R */ #else /* HAVE GETPWNAM_R */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
pwp = getpwnam(username); pwp = getpwnam(username);
@@ -324,13 +336,25 @@ METHOD(capabilities_t, resolve_gid, bool,
#ifdef HAVE_GETGRNAM_R #ifdef HAVE_GETGRNAM_R
struct group group; struct group group;
char buf[1024]; size_t buflen = 1024;
char *buf = NULL;
err = getgrnam_r(groupname, &group, buf, sizeof(buf), &grp); while (TRUE)
if (grp)
{ {
this->gid = grp->gr_gid; buf = realloc(buf, buflen);
err = getgrnam_r(groupname, &group, buf, buflen, &grp);
if (err == ERANGE)
{
buflen *= 2;
continue;
}
if (grp)
{
this->gid = grp->gr_gid;
}
break;
} }
free(buf);
#else /* HAVE_GETGRNAM_R */ #else /* HAVE_GETGRNAM_R */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
grp = getgrnam(groupname); grp = getgrnam(groupname);
@@ -362,12 +386,24 @@ static bool init_supplementary_groups(private_capabilities_t *this)
#ifdef HAVE_GETPWUID_R #ifdef HAVE_GETPWUID_R
struct passwd pwd; struct passwd pwd;
char buf[1024]; size_t buflen = 1024;
char *buf = NULL;
if (getpwuid_r(this->uid, &pwd, buf, sizeof(buf), &pwp) == 0 && pwp) while (TRUE)
{ {
res = initgroups(pwp->pw_name, this->gid); buf = realloc(buf, buflen);
if (getpwuid_r(this->uid, &pwd, buf, buflen, &pwp) == ERANGE)
{
buflen *= 2;
continue;
}
if (pwp)
{
res = initgroups(pwp->pw_name, this->gid);
}
break;
} }
free(buf);
#else /* HAVE_GETPWUID_R */ #else /* HAVE_GETPWUID_R */
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
pwp = getpwuid(this->uid); pwp = getpwuid(this->uid);