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_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_nisplus_setgrent (int stayopen) { enum nss_status status; __libc_lock_lock (lock); internal_endgrent (); // XXX We need to be able to set errno. Pass in new parameter. int err; status = internal_setgrent (&err); __libc_lock_unlock (lock); return status; }
static enum nss_status internal_nisplus_getgrent_r (struct group *gr, char *buffer, size_t buflen, int *errnop) { int parse_res = -1; enum nss_status retval = NSS_STATUS_SUCCESS; /* Get the next entry until we found a correct one. */ do { nis_error status; nis_result result; memset (&result, '\0', sizeof (result)); if (cursor.n_bytes == NULL) { if (ibreq == NULL) { retval = internal_setgrent (errnop); if (retval != NSS_STATUS_SUCCESS) return retval; } status = __do_niscall3 (&bptr, NIS_IBFIRST, (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, (caddr_t) &result, 0, NULL); } else { ibreq->ibr_cookie.n_bytes = cursor.n_bytes; ibreq->ibr_cookie.n_len = cursor.n_len; status = __do_niscall3 (&bptr, NIS_IBNEXT, (xdrproc_t) _xdr_ib_request, (caddr_t) ibreq, (xdrproc_t) _xdr_nis_result, (caddr_t) &result, 0, NULL); ibreq->ibr_cookie.n_bytes = NULL; ibreq->ibr_cookie.n_len = 0; } if (status != NIS_SUCCESS) return niserr2nss (status); if (NIS_RES_STATUS (&result) == NIS_NOTFOUND) { /* No more entries on this server. This means we have to go to the next server on the path. */ status = __follow_path (&tablepath, &tableptr, ibreq, &bptr); if (status != NIS_SUCCESS) return niserr2nss (status); directory_obj *newdir = NULL; dir_binding newbptr; status = __prepare_niscall (ibreq->ibr_name, &newdir, &newbptr, 0); if (status != NIS_SUCCESS) return niserr2nss (status); nis_free_directory (dir); dir = newdir; __nisbind_destroy (&bptr); bptr = newbptr; xdr_free ((xdrproc_t) xdr_netobj, (char *) &result.cookie); result.cookie.n_bytes = NULL; result.cookie.n_len = 0; parse_res = 0; goto next; } else if (NIS_RES_STATUS (&result) != NIS_SUCCESS) return niserr2nss (NIS_RES_STATUS (&result)); parse_res = _nss_nisplus_parse_grent (&result, gr, buffer, buflen, errnop); if (__glibc_unlikely (parse_res == -1)) { *errnop = ERANGE; retval = NSS_STATUS_TRYAGAIN; goto freeres; } next: /* Free the old cursor. */ xdr_free ((xdrproc_t) xdr_netobj, (char *) &cursor); /* Remember the new one. */ cursor.n_bytes = result.cookie.n_bytes; cursor.n_len = result.cookie.n_len; /* Free the result structure. NB: we do not remove the cookie. */ result.cookie.n_bytes = NULL; result.cookie.n_len = 0; freeres: xdr_free ((xdrproc_t) _xdr_nis_result, (char *) &result); memset (&result, '\0', sizeof (result)); } while (!parse_res); return retval; }
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; }