]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
user-util: Add helper functions for gid lists operations
authorDariusz Gadomski <dgadomski@gmail.com>
Wed, 8 Jan 2020 15:22:29 +0000 (16:22 +0100)
committerDariusz Gadomski <dgadomski@gmail.com>
Mon, 13 Jan 2020 09:29:10 +0000 (10:29 +0100)
src/basic/user-util.c
src/basic/user-util.h

index 985a669a1b1b04292f98c43cff05a4b12bcd8aee..571578c4e4946638217bf17e4b0bc306347796f1 100644 (file)
@@ -404,11 +404,16 @@ char* gid_to_name(gid_t gid) {
         return ret;
 }
 
+static bool gid_list_has(const gid_t *list, size_t size, gid_t val) {
+        for (size_t i = 0; i < size; i++)
+                if (list[i] == val)
+                        return true;
+        return false;
+}
+
 int in_gid(gid_t gid) {
-        _cleanup_free_ gid_t *allocated = NULL;
-        gid_t local[16], *p = local;
-        int ngroups = ELEMENTSOF(local);
-        unsigned attempt = 0;
+        _cleanup_free_ gid_t *gids = NULL;
+        int ngroups;
 
         if (getgid() == gid)
                 return 1;
@@ -419,6 +424,57 @@ int in_gid(gid_t gid) {
         if (!gid_is_valid(gid))
                 return -EINVAL;
 
+        ngroups = getgroups_alloc(&gids);
+        if (ngroups < 0)
+                return ngroups;
+
+        return gid_list_has(gids, ngroups, gid);
+}
+
+int in_group(const char *name) {
+        int r;
+        gid_t gid;
+
+        r = get_group_creds(&name, &gid, 0);
+        if (r < 0)
+                return r;
+
+        return in_gid(gid);
+}
+
+int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **ret) {
+        size_t nresult = 0;
+        assert(ret);
+
+        if (size2 > INT_MAX - size1)
+                return -ENOBUFS;
+
+        gid_t *buf = new(gid_t, size1 + size2);
+        if (!buf)
+                return -ENOMEM;
+
+        /* Duplicates need to be skipped on merging, otherwise they'll be passed on and stored in the kernel. */
+        for (size_t i = 0; i < size1; i++)
+                if (!gid_list_has(buf, nresult, list1[i]))
+                        buf[nresult++] = list1[i];
+        for (size_t i = 0; i < size2; i++)
+                if (!gid_list_has(buf, nresult, list2[i]))
+                        buf[nresult++] = list2[i];
+        *ret = buf;
+        return (int)nresult;
+}
+
+int getgroups_alloc(gid_t** gids) {
+        gid_t *allocated;
+        _cleanup_free_  gid_t *p = NULL;
+        int ngroups = 8;
+        unsigned attempt = 0;
+
+        allocated = new(gid_t, ngroups);
+        if (!allocated)
+                return -ENOMEM;
+        p = allocated;
+
         for (;;) {
                 ngroups = getgroups(ngroups, p);
                 if (ngroups >= 0)
@@ -447,22 +503,8 @@ int in_gid(gid_t gid) {
                 p = allocated;
         }
 
-        for (int i = 0; i < ngroups; i++)
-                if (p[i] == gid)
-                        return true;
-
-        return false;
-}
-
-int in_group(const char *name) {
-        int r;
-        gid_t gid;
-
-        r = get_group_creds(&name, &gid, 0);
-        if (r < 0)
-                return r;
-
-        return in_gid(gid);
+        *gids = TAKE_PTR(p);
+        return ngroups;
 }
 
 int get_home_dir(char **_h) {
index 7488071086ef135781d78d9384eab27e4bbfd5a9..e11dd9b379c0ef20d70e32543f789fbf2176a46d 100644 (file)
@@ -42,6 +42,9 @@ char* gid_to_name(gid_t gid);
 int in_gid(gid_t gid);
 int in_group(const char *name);
 
+int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **result);
+int getgroups_alloc(gid_t** gids);
+
 int get_home_dir(char **ret);
 int get_shell(char **_ret);