enum nss_status _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *tmpbuf; enum nss_status status; ent_t intern = { TRUE, NULL, {NULL, 0, 0} }; status = internal_setgrent (&intern); if (status != NSS_STATUS_SUCCESS) return status; tmpbuf = __alloca (buflen); do { while ((status = internal_getgrent_r (&intern, tmpbuf, buflen, user, group, start, size, groupsp, limit, errnop)) == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); } while (status == NSS_STATUS_SUCCESS); internal_endgrent (&intern); return NSS_STATUS_SUCCESS; }
enum nss_status _nss_sss_getgrent_r(struct group *result, char *buffer, size_t buflen, int *errnop) { enum nss_status nret; sss_nss_lock(); nret = internal_getgrent_r(result, buffer, buflen, errnop); sss_nss_unlock(); return nret; }
enum nss_status _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *tmpbuf; enum nss_status status; ent_t intern = { true, false, false, NULL, {NULL, 0, 0} }; bool use_malloc = false; status = internal_setgrent (&intern); if (status != NSS_STATUS_SUCCESS) return status; tmpbuf = __alloca (buflen); do { while ((status = internal_getgrent_r (&intern, tmpbuf, buflen, user, group, start, size, groupsp, limit, errnop)) == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) if (__libc_use_alloca (buflen * 2)) tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); else { buflen *= 2; char *newbuf = realloc (use_malloc ? tmpbuf : NULL, buflen); if (newbuf == NULL) { status = NSS_STATUS_TRYAGAIN; goto done; } use_malloc = true; tmpbuf = newbuf; } } while (status == NSS_STATUS_SUCCESS); status = NSS_STATUS_SUCCESS; done: if (use_malloc) free (tmpbuf); internal_endgrent (&intern); return status; }
enum nss_status _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { /* We always need the domain name. */ char *domainname; if (yp_get_default_domain (&domainname)) return NSS_STATUS_UNAVAIL; /* Check whether we are supposed to use the netid.byname map. */ if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) { /* We need the user ID. */ uid_t uid; if (get_uid (user, &uid) == 0 && initgroups_netid (uid, group, start, size, groupsp, limit, errnop, domainname) == NSS_STATUS_SUCCESS) return NSS_STATUS_SUCCESS; } struct group grpbuf, *g; size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *tmpbuf; enum nss_status status; intern_t intern = { NULL, NULL, 0 }; gid_t *groups = *groupsp; status = internal_setgrent (domainname, &intern); if (status != NSS_STATUS_SUCCESS) return status; tmpbuf = __alloca (buflen); while (1) { while ((status = internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, &intern)) == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); if (status != NSS_STATUS_SUCCESS) { if (status == NSS_STATUS_NOTFOUND) status = NSS_STATUS_SUCCESS; goto done; } g = &grpbuf; if (g->gr_gid != group) { char **m; for (m = g->gr_mem; *m != NULL; ++m) if (strcmp (*m, user) == 0) { /* Matches user. Insert this group. */ if (*start == *size) { /* Need a bigger buffer. */ gid_t *newgroups; long int newsize; if (limit > 0 && *size == limit) /* We reached the maximum. */ goto done; if (limit <= 0) newsize = 2 * *size; else newsize = MIN (limit, 2 * *size); newgroups = realloc (groups, newsize * sizeof (*groups)); if (newgroups == NULL) { status = NSS_STATUS_TRYAGAIN; *errnop = errno; goto done; } *groupsp = groups = newgroups; *size = newsize; } groups[*start] = g->gr_gid; *start += 1; break; } } } done: while (intern.start != NULL) { intern.next = intern.start; intern.start = intern.start->next; free (intern.next); } return status; }
static enum nss_status internal_getgrent_r(struct group *result, char *buffer, size_t buflen, int *errnop) { struct sss_cli_req_data rd; struct sss_nss_gr_rep grrep; uint8_t *repbuf; size_t replen; enum nss_status nret; uint32_t num_entries; int ret; /* Caught once glibc passing in buffer == 0x0 */ if (!buffer || !buflen) return ERANGE; /* if there are leftovers return the next one */ if (sss_nss_getgrent_data.data != NULL && sss_nss_getgrent_data.ptr < sss_nss_getgrent_data.len) { repbuf = (uint8_t *)sss_nss_getgrent_data.data + sss_nss_getgrent_data.ptr; replen = sss_nss_getgrent_data.len - sss_nss_getgrent_data.ptr; grrep.result = result; grrep.buffer = buffer; grrep.buflen = buflen; ret = sss_nss_getgr_readrep(&grrep, repbuf, &replen); if (ret) { *errnop = ret; return NSS_STATUS_TRYAGAIN; } /* advance buffer pointer */ sss_nss_getgrent_data.ptr = sss_nss_getgrent_data.len - replen; return NSS_STATUS_SUCCESS; } /* release memory if any */ sss_nss_getgrent_data_clean(); /* retrieve no more than SSS_NSS_MAX_ENTRIES at a time */ num_entries = SSS_NSS_MAX_ENTRIES; rd.len = sizeof(uint32_t); rd.data = &num_entries; nret = sss_nss_make_request(SSS_NSS_GETGRENT, &rd, &repbuf, &replen, errnop); if (nret != NSS_STATUS_SUCCESS) { return nret; } /* no results if not found */ if ((((uint32_t *)repbuf)[0] == 0) || (replen - 8 == 0)) { free(repbuf); return NSS_STATUS_NOTFOUND; } sss_nss_getgrent_data.data = repbuf; sss_nss_getgrent_data.len = replen; sss_nss_getgrent_data.ptr = 8; /* skip metadata fields */ /* call again ourselves, this will return the first result */ return internal_getgrent_r(result, buffer, buflen, errnop); }