]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
user-util: add getgrouplist_malloc and initgroups_wrapper
authorZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Thu, 21 May 2026 07:55:56 +0000 (09:55 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@amutable.com>
Thu, 2 Jul 2026 15:19:18 +0000 (17:19 +0200)
src/basic/user-util.c
src/basic/user-util.h

index 5c7f783f5ce7a2dc0dee78e6fa283bab3c2d7110..fe4c0e6a36858f6b915705f50219a00c104a50f1 100644 (file)
@@ -1445,6 +1445,50 @@ ssize_t lookup_groups_in_files(
         return n_arr;
 }
 
+int getgrouplist_malloc(const char *user, gid_t gid, gid_t **ret) {
+#if BUILD_STATIC
+        return lookup_groups_in_files(GROUP_FILES, user, gid, ret);
+#else
+        int ngroups_max = sysconf_ngroups_max();
+        if (ngroups_max < 0)
+                return ngroups_max;
+
+        _cleanup_free_ gid_t *gids = new(gid_t, ngroups_max);
+        if (!gids)
+                return -ENOMEM;
+
+        int k = ngroups_max;
+        if (getgrouplist(user, gid, gids, &k) < 0)
+                return -EIO;  /* getgrouplist does not set errno */
+
+        if (ret)
+                *ret = TAKE_PTR(gids);
+        return k;
+#endif
+}
+
+int initgroups_wrapper(const char *user, gid_t gid) {
+#if BUILD_STATIC
+        _cleanup_free_ gid_t *groups = NULL;
+        int r, n_groups;
+
+        n_groups = getgrouplist_malloc(user, gid, &groups);
+        if (n_groups <= 0)
+                return n_groups;
+
+        /* Try to set the maximum number of groups the kernel can handle. This is what glibc does. */
+        for (; n_groups > 0; n_groups--) {
+                r = RET_NERRNO(setgroups(n_groups, groups));
+                if (r != -EINVAL)
+                        break;
+        }
+
+        return r;
+#else
+        return RET_NERRNO(initgroups(user, gid));
+#endif
+}
+
 #if !BUILD_STATIC
 
 static size_t getgr_buffer_size(void) {
index 6f90c8c4530e12d62bb29314b4fc2db2ed893dda..ab9222c5003ec15777650ea17cfa8d23b37d266b 100644 (file)
@@ -189,11 +189,14 @@ int lookup_grent_in_files(
                 const char *name,
                 gid_t gid,
                 struct group **ret);
+
 ssize_t lookup_groups_in_files(
                 char * const *files,
                 const char *name,
                 gid_t gid,
                 gid_t **ret);
+int getgrouplist_malloc(const char *user, gid_t gid, gid_t **ret);
+int initgroups_wrapper(const char *user, gid_t gid);
 
 int getpwuid_malloc(uid_t uid, struct passwd **ret);
 int getpwnam_malloc(const char *name, struct passwd **ret);