nwrap: Implement initgroups() using nwrap_getgrouplist()
authorPavel Filipenský <pfilipensky@samba.org>
Mon, 16 Jan 2023 19:58:17 +0000 (20:58 +0100)
committerAndreas Schneider <asn@samba.org>
Tue, 24 Jan 2023 08:56:35 +0000 (09:56 +0100)
Signed-off-by: Pavel Filipenský <pfilipensky@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
src/nss_wrapper.c

index 2eeae8da31c689d5fd05de71ac8de474c659ad90..b629432b253af1ff993a2235d86be5b91d7e59cf 100644 (file)
@@ -54,6 +54,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <limits.h>
 
 #include <netinet/in.h>
 
@@ -841,6 +842,14 @@ static int nwrap_convert_he_ai(const struct hostent *he,
                               struct addrinfo **pai,
                               bool skip_canonname);
 
+#ifdef HAVE_GETGROUPLIST
+static int nwrap_getgrouplist(const char *user,
+                             gid_t group,
+                             long int *size,
+                             gid_t **groupsp,
+                             long int limit);
+#endif
+
 /*
  * VECTORS
  */
@@ -5320,7 +5329,49 @@ void endpwent(void)
 
 static int nwrap_initgroups(const char *user, gid_t group)
 {
+#if defined(NGROUPS_MAX) && NGROUPS_MAX == 0
+       /* No extra groups allowed.  */
        return 0;
+#elif !defined(HAVE_GETGROUPLIST)
+       return 0;
+#else
+       long int size;
+       long int limit;
+       gid_t *groups;
+       int ngroups;
+       int result;
+       const char *env = getenv("UID_WRAPPER");
+
+       if (env == NULL || env[0] != '1') {
+               NWRAP_LOG(NWRAP_LOG_WARN,
+                         "initgroups() requires uid_wrapper to work!");
+               return 0;
+       }
+
+       limit = sysconf(_SC_NGROUPS_MAX);
+       if (limit > 0) {
+               size = MIN(limit, 64);
+       } else {
+               size = 16;
+       }
+
+       groups = (gid_t *)malloc(size * sizeof(gid_t));
+       if (groups == NULL) {
+               /* No more memory.  */
+               return -1;
+       }
+
+       ngroups = nwrap_getgrouplist(user, group, &size, &groups, limit);
+
+       /* Try to set the maximum number of groups the kernel can handle.  */
+       do {
+               result = setgroups(ngroups, groups);
+       } while (result == -1 && errno == EINVAL && --ngroups > 0);
+
+       free(groups);
+
+       return result;
+#endif
 }
 
 int initgroups(const char *user, gid_t group)