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;
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)
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) {
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);