From b01b331afe1f7215a4bae465928db5d050f8c2b9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 23 Jun 2015 09:46:18 +0200 Subject: [PATCH] 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. --- src/libstrongswan/utils/capabilities.c | 60 ++++++++++++++++++++------ 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 923b7d4db..ce5f550b5 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Tobias Brunner + * Copyright (C) 2012-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2012 Martin Willi * Copyright (C) 2012 revosec AG @@ -288,13 +288,25 @@ METHOD(capabilities_t, resolve_uid, bool, #ifdef HAVE_GETPWNAM_R struct passwd passwd; - char buf[1024]; + size_t buflen = 1024; + char *buf = NULL; - err = getpwnam_r(username, &passwd, buf, sizeof(buf), &pwp); - if (pwp) + while (TRUE) { - 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 */ this->mutex->lock(this->mutex); pwp = getpwnam(username); @@ -324,13 +336,25 @@ METHOD(capabilities_t, resolve_gid, bool, #ifdef HAVE_GETGRNAM_R struct group group; - char buf[1024]; + size_t buflen = 1024; + char *buf = NULL; - err = getgrnam_r(groupname, &group, buf, sizeof(buf), &grp); - if (grp) + while (TRUE) { - 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 */ this->mutex->lock(this->mutex); grp = getgrnam(groupname); @@ -362,12 +386,24 @@ static bool init_supplementary_groups(private_capabilities_t *this) #ifdef HAVE_GETPWUID_R 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 */ this->mutex->lock(this->mutex); pwp = getpwuid(this->uid);