+enum nss_status
+check_nonlocal_group(const char *user, struct group *grp, int *errnop)
+{
+ enum nss_status status = NSS_STATUS_SUCCESS;
+ int old_errno = errno;
+ char *end;
+ unsigned long gid;
+
+ errno = 0;
+ gid = strtoul(grp->gr_name, &end, 10);
+ if (errno == 0 && *end == '\0' && (gid_t)gid == gid) {
+ errno = old_errno;
+ status = check_nonlocal_gid(user, gid, errnop);
+ } else
+ errno = old_errno;
+ if (status != NSS_STATUS_SUCCESS)
+ return status;
+
+ return check_nonlocal_gid(user, grp->gr_gid, errnop);
+}
+
+enum nss_status
+get_local_group(const char *name, struct group *grp, char **buffer, int *errnop)
+{
+ static const char *fct_name = "getgrnam_r";
+ static service_user *startp = NULL;
+ static void *fct_start = NULL;
+ enum nss_status status;
+ service_user *nip;
+ union {
+ enum nss_status (*l)(const char *name, struct group *grp,
+ char *buffer, size_t buflen, int *errnop);
+ void *ptr;
+ } fct;
+ size_t buflen;
+ int old_errno = errno;
+
+ buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
+ *buffer = malloc(buflen);
+ errno = old_errno;
+ if (*buffer == NULL) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ if (fct_start == NULL &&
+ __nss_group_lookup(&startp, fct_name, &fct_start) != 0) {
+ free(*buffer);
+ *buffer = NULL;
+ return NSS_STATUS_UNAVAIL;
+ }
+ nip = startp;
+ fct.ptr = fct_start;
+ do {
+ morebuf:
+ if (fct.l == _nss_nonlocal_getgrnam_r)
+ status = NSS_STATUS_NOTFOUND;
+ else
+ status = DL_CALL_FCT(fct.l, (name, grp, *buffer, buflen, errnop));
+ if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE) {
+ free(*buffer);
+ buflen *= 2;
+ *buffer = malloc(buflen);
+ errno = old_errno;
+ if (*buffer == NULL) {
+ *errnop = ENOMEM;
+ return NSS_STATUS_TRYAGAIN;
+ }
+ goto morebuf;
+ }
+ } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
+
+ if (status != NSS_STATUS_SUCCESS) {
+ free(*buffer);
+ *buffer = NULL;
+ }
+
+ return status;
+}