nwrap: Implement getgrouplist() correctly
authorPavel Filipenský <pfilipensky@samba.org>
Mon, 16 Jan 2023 19:52:45 +0000 (20:52 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 24 Jan 2023 08:56:35 +0000 (09:56 +0100)
The main job is done in nwrap_getgrouplist() that will be used also by
initgroups() next.

Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/nss_wrapper.c

index b2e9f2af1d061dd9666b3683da78cea5f62ccd33..2eeae8da31c689d5fd05de71ac8de474c659ad90 100644 (file)
@@ -5618,81 +5618,85 @@ void endgrent(void)
  ***************************************************************************/
 
 #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