***************************************************************************/
#ifdef HAVE_GETGROUPLIST
-static int nwrap_getgrouplist(const char *user, gid_t group,
- gid_t *groups, int *ngroups)
-{
- struct group *grp;
- gid_t *groups_tmp;
- int count = 1;
-
- NWRAP_LOG(NWRAP_LOG_DEBUG, "getgrouplist called for %s", user);
-
- groups_tmp = (gid_t *)malloc(count * sizeof(gid_t));
- if (!groups_tmp) {
- NWRAP_LOG(NWRAP_LOG_ERROR, "Out of memory");
- errno = ENOMEM;
- return -1;
- }
- groups_tmp[0] = group;
-
- nwrap_setgrent();
- while ((grp = nwrap_getgrent()) != NULL) {
- int i = 0;
-
- NWRAP_LOG(NWRAP_LOG_DEBUG,
- "Inspecting %s for group membership",
- grp->gr_name);
-
- for (i=0; grp->gr_mem && grp->gr_mem[i] != NULL; i++) {
-
- if (group != grp->gr_gid &&
- (strcmp(user, grp->gr_mem[i]) == 0)) {
+static int nwrap_getgrouplist(const char *user,
+ gid_t group,
+ long int *size,
+ gid_t **groupsp,
+ long int limit)
+{
+ enum nss_status status = NSS_STATUS_UNAVAIL;
+ /* Start is one, because we have the first group as parameter. */
+ long int start = 1;
+ size_t i;
- NWRAP_LOG(NWRAP_LOG_DEBUG,
- "%s is member of %s",
- user,
- grp->gr_name);
+ /* Never store more than the starting *SIZE number of elements. */
+ assert(*size > 0);
+ (*groupsp)[0] = group;
- groups_tmp = (gid_t *)realloc(groups_tmp, (count + 1) * sizeof(gid_t));
- if (!groups_tmp) {
- NWRAP_LOG(NWRAP_LOG_ERROR,
- "Out of memory");
- errno = ENOMEM;
- return -1;
- }
- groups_tmp[count] = grp->gr_gid;
+ for (i = 0; i < nwrap_main_global->num_backends; i++) {
+ struct nwrap_backend *b = &nwrap_main_global->backends[i];
+ long int prev_start = start;
+ long int cnt = prev_start;
+
+ status = b->ops->nw_initgroups_dyn(b,
+ user,
+ group,
+ &start,
+ size,
+ groupsp,
+ limit,
+ &errno);
+
+ /* Remove duplicates. */
+ while (cnt < start) {
+ long int inner;
+ for (inner = 0; inner < prev_start; ++inner)
+ if ((*groupsp)[inner] == (*groupsp)[cnt])
+ break;
- count++;
- }
+ if (inner < prev_start)
+ (*groupsp)[cnt] = (*groupsp)[--start];
+ else
+ ++cnt;
}
+ NWRAP_LOG(NWRAP_LOG_DEBUG,
+ "Resource '%s' returned status=%d and increased "
+ "count of groups to %ld",
+ b->name,
+ status,
+ start);
}
+ return start;
+}
- nwrap_endgrent();
+int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
+{
+ long int size;
+ int total, retval;
+ gid_t *newgroups;
- NWRAP_LOG(NWRAP_LOG_DEBUG,
- "%s is member of %d groups",
- user, *ngroups);
+ if (!nss_wrapper_enabled()) {
+ return libc_getgrouplist(user, group, groups, ngroups);
+ }
- if (*ngroups < count) {
- *ngroups = count;
- free(groups_tmp);
+ size = MAX(1, *ngroups);
+ newgroups = (gid_t *)malloc(size * sizeof(gid_t));
+ if (newgroups == NULL) {
return -1;
}
- *ngroups = count;
- memcpy(groups, groups_tmp, count * sizeof(gid_t));
- free(groups_tmp);
+ total = nwrap_getgrouplist(user, group, &size, &newgroups, -1);
- return count;
-}
-
-int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups)
-{
- if (!nss_wrapper_enabled()) {
- return libc_getgrouplist(user, group, groups, ngroups);
+ if (groups != NULL) {
+ memcpy(groups, newgroups, MIN(*ngroups, total) * sizeof(gid_t));
}
- return nwrap_getgrouplist(user, group, groups, ngroups);
+ free(newgroups);
+
+ retval = total > *ngroups ? -1 : total;
+ *ngroups = total;
+
+ return retval;
}
#endif