From: Dariusz Gadomski Date: Wed, 8 Jan 2020 15:22:29 +0000 (+0100) Subject: user-util: Add helper functions for gid lists operations X-Git-Tag: v245-rc1~139^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0c5d667932f8abaf02814ee9ada6d0e63d63f8bb;p=thirdparty%2Fsystemd.git user-util: Add helper functions for gid lists operations --- diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 985a669a1b1..571578c4e49 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -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) { diff --git a/src/basic/user-util.h b/src/basic/user-util.h index 7488071086e..e11dd9b379c 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -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);