struct group *fgetgrent(FILE *f) { static char *line, **mem; static struct group gr; size_t size=0, nmem=0; return __getgrent_a(f, &gr, &line, &size, &mem, &nmem); }
struct group *getgrent() { static char *line, **mem; static struct group gr; size_t size=0, nmem=0; if (!f) f = fopen("/etc/group", "rb"); if (!f) return 0; return __getgrent_a(f, &gr, &line, &size, &mem, &nmem); }
static int getgr_r(const char *name, gid_t gid, struct group *gr, char *buf, size_t size, struct group **res) { FILE *f; char *line = 0; size_t len = 0; char **mem = 0; size_t nmem = 0; int rv = 0; size_t i; int cs; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); f = fopen("/etc/group", "rbe"); if (!f) { rv = errno; goto done; } *res = 0; while (__getgrent_a(f, gr, &line, &len, &mem, &nmem)) { if (name && !strcmp(name, gr->gr_name) || !name && gr->gr_gid == gid) { if (size < len + (nmem+1)*sizeof(char *) + 32) { rv = ERANGE; break; } *res = gr; buf += (16-(uintptr_t)buf)%16; gr->gr_mem = (void *)buf; buf += (nmem+1)*sizeof(char *); memcpy(buf, line, len); FIX(name); FIX(passwd); for (i=0; mem[i]; i++) gr->gr_mem[i] = mem[i]-line+buf; gr->gr_mem[i] = 0; break; } } free(mem); free(line); fclose(f); done: pthread_setcancelstate(cs, 0); return rv; }
int __getgr_a(const char* name, gid_t gid, struct group* gr, char** buf, size_t* size, char*** mem, size_t* nmem, struct group** res) { FILE* f; int rv = 0; *res = 0; f = fopen("/etc/group", "rbe"); if (!f) { rv = errno; goto done; } while (!(rv = __getgrent_a(f, gr, buf, size, mem, nmem, res)) && *res) { if ((name && !strcmp(name, (*res)->gr_name)) || (!name && (*res)->gr_gid == gid)) { break; } } fclose(f); if (!*res && (rv == 0 || rv == ENOENT || rv == ENOTDIR)) { int32_t req = name ? GETGRBYNAME : GETGRBYGID; int32_t i; const char* key; int32_t groupbuf[GR_LEN] = {}; size_t len = 0; size_t grlist_len = 0; char gidbuf[11] = {}; int swap = 0; char* ptr; if (name) { key = name; } else { if (gid > UINT32_MAX) { rv = 0; goto done; } key = itoa(gidbuf, gid); } f = __nscd_query(req, key, groupbuf, sizeof groupbuf, &swap); if (!f) { rv = errno; goto done; } if (!groupbuf[GRFOUND]) { rv = 0; goto cleanup_f; } if (!groupbuf[GRNAMELEN] || !groupbuf[GRPASSWDLEN]) { rv = EIO; goto cleanup_f; } if (groupbuf[GRNAMELEN] > SIZE_MAX - groupbuf[GRPASSWDLEN]) { rv = ENOMEM; goto cleanup_f; } len = groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; for (i = 0; i < groupbuf[GRMEMCNT]; i++) { uint32_t name_len; if (fread(&name_len, sizeof name_len, 1, f) < 1) { rv = ferror(f) ? errno : EIO; goto cleanup_f; } if (swap) { name_len = bswap_32(name_len); } if (name_len > SIZE_MAX - grlist_len || name_len > SIZE_MAX - len) { rv = ENOMEM; goto cleanup_f; } len += name_len; grlist_len += name_len; } if (len > *size || !*buf) { char* tmp = realloc(*buf, len); if (!tmp) { rv = errno; goto cleanup_f; } *buf = tmp; *size = len; } if (!fread(*buf, len, 1, f)) { rv = ferror(f) ? errno : EIO; goto cleanup_f; } if (groupbuf[GRMEMCNT] + 1 > *nmem) { if (groupbuf[GRMEMCNT] + 1 > SIZE_MAX / sizeof(char*)) { rv = ENOMEM; goto cleanup_f; } char** tmp = realloc(*mem, (groupbuf[GRMEMCNT] + 1) * sizeof(char*)); if (!tmp) { rv = errno; goto cleanup_f; } *mem = tmp; *nmem = groupbuf[GRMEMCNT] + 1; } if (groupbuf[GRMEMCNT]) { mem[0][0] = *buf + groupbuf[GRNAMELEN] + groupbuf[GRPASSWDLEN]; for (ptr = mem[0][0], i = 0; ptr != mem[0][0] + grlist_len; ptr++) if (!*ptr) mem[0][++i] = ptr + 1; mem[0][i] = 0; if (i != groupbuf[GRMEMCNT]) { rv = EIO; goto cleanup_f; } } else { mem[0][0] = 0; } gr->gr_name = *buf; gr->gr_passwd = gr->gr_name + groupbuf[GRNAMELEN]; gr->gr_gid = groupbuf[GRGID]; gr->gr_mem = *mem; if (gr->gr_passwd[-1] || gr->gr_passwd[groupbuf[GRPASSWDLEN] - 1]) { rv = EIO; goto cleanup_f; } if ((name && strcmp(name, gr->gr_name)) || (!name && gid != gr->gr_gid)) { rv = EIO; goto cleanup_f; } *res = gr; cleanup_f: fclose(f); goto done; } done: if (rv) errno = rv; return rv; }