Issue #243: Cannot look up group "shellinabox" at service start

_SC_GETGR_R_SIZE_MAX was treated as a maximum buffer size while
it should only be a proposition for an initial size.

The buffer size is now increased dynamically if the initial size
is not sufficient.
This commit is contained in:
tickelton 2015-05-08 09:03:16 +02:00
parent 5372964801
commit 5f1aaea6f1

View file

@ -363,8 +363,12 @@ static int getgrnam_r(const char *name, struct group *grp, char *buf,
#endif #endif
gid_t getGroupId(const char *name) { gid_t getGroupId(const char *name) {
static const long gr_max = 64 * 1024;
struct group grbuf, *gr; struct group grbuf, *gr;
char *temp;
char *buf; char *buf;
int ret;
int gr_baselen;
#ifdef _SC_GETGR_R_SIZE_MAX #ifdef _SC_GETGR_R_SIZE_MAX
int gr_len = sysconf(_SC_GETGR_R_SIZE_MAX); int gr_len = sysconf(_SC_GETGR_R_SIZE_MAX);
if (gr_len <= 0) { if (gr_len <= 0) {
@ -373,29 +377,47 @@ gid_t getGroupId(const char *name) {
#else #else
int gr_len = 4096; int gr_len = 4096;
#endif #endif
gr_baselen = gr_len;
check(buf = malloc(gr_len)); check(buf = malloc(gr_len));
if (getgrnam_r(name, &grbuf, buf, gr_len, &gr) || !gr) { for(;;) {
// Maybe, this system does not have a "nogroup" group. Substitute the errno = 0;
// group of the "nobody" user. ret = getgrnam_r(name, &grbuf, buf, gr_len, &gr);
if (!strcmp(name, "nogroup")) { if(!ret) {
struct passwd pwbuf, *pw; if(gr) {
#ifdef _SC_GETPW_R_SIZE_MAX break;
int pw_len = sysconf(_SC_GETPW_R_SIZE_MAX); } else if(!strcmp(name, "nogroup")) {
if (pw_len <= 0) { // Maybe, this system does not have a "nogroup" group. Substitute the
pw_len = 4096; // group of the "nobody" user.
struct passwd pwbuf, *pw;
#ifdef _SC_GETPW_R_SIZE_MAX
int pw_len = sysconf(_SC_GETPW_R_SIZE_MAX);
if (pw_len <= 0) {
pw_len = 4096;
}
#else
int pw_len = 4096;
#endif
if (pw_len > gr_len) {
check(buf = realloc(buf, pw_len));
}
if (!getpwnam_r("nobody", &pwbuf, buf, pw_len, &pw) && pw) {
debug("Substituting \"nobody's\" primary group for \"nogroup\"");
gid_t gid = pw->pw_gid;
free(buf);
return gid;
}
} }
#else }
int pw_len = 4096; if(ret && errno == ERANGE) {
#endif if ((gr_len + gr_baselen) < gr_len || (gr_len + gr_baselen) > gr_max) {
if (pw_len > gr_len) { fatal("Cannot look up group \"%s\": buffer limit reached", name);
check(buf = realloc(buf, pw_len)); break;
}
if (!getpwnam_r("nobody", &pwbuf, buf, pw_len, &pw) && pw) {
debug("Substituting \"nobody's\" primary group for \"nogroup\"");
gid_t gid = pw->pw_gid;
free(buf);
return gid;
} }
// grow the buffer by 'gr_baselen' each time getgrnam_r fails
gr_len += gr_baselen;
check(temp = realloc (buf, gr_len));
buf = temp;
continue;
} }
fatal("Cannot look up group \"%s\"", name); fatal("Cannot look up group \"%s\"", name);
} }