user-util: add lookup_groups_in_files
This commit is contained in:
@@ -1366,6 +1366,67 @@ int sysconf_ngroups_max(void) {
|
||||
return ngroups_max;
|
||||
}
|
||||
|
||||
ssize_t lookup_groups_in_files(
|
||||
char * const *files,
|
||||
const char *name,
|
||||
gid_t gid,
|
||||
gid_t **ret) {
|
||||
|
||||
_cleanup_free_ gid_t *arr = NULL;
|
||||
ssize_t n_arr = 0;
|
||||
int r;
|
||||
|
||||
assert(files);
|
||||
assert(name);
|
||||
assert(gid_is_valid(gid));
|
||||
|
||||
int ngroups_max = sysconf_ngroups_max();
|
||||
if (ngroups_max < 0)
|
||||
return ngroups_max;
|
||||
|
||||
if (!GREEDY_REALLOC(arr, n_arr + 1))
|
||||
return -ENOMEM;
|
||||
arr[n_arr++] = gid;
|
||||
|
||||
STRV_FOREACH(fname, files) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
struct group *gr;
|
||||
|
||||
r = fopen_unlocked(*fname, "re", &f);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while ((r = fgetgrent_sane(f, &gr)) > 0) {
|
||||
if (gid == gr->gr_gid)
|
||||
continue;
|
||||
|
||||
/* Deduplicate groups, in case the group is doubly defined in the same or
|
||||
* different files. */
|
||||
if (gid_list_has(arr, n_arr, gr->gr_gid))
|
||||
continue;
|
||||
|
||||
if (!strv_contains(gr->gr_mem, name))
|
||||
continue;
|
||||
|
||||
/* Do not allow more than _SC_NGROUPS_MAX. */
|
||||
if (n_arr >= ngroups_max)
|
||||
return -ENOBUFS;
|
||||
|
||||
if (!GREEDY_REALLOC(arr, n_arr + 1))
|
||||
return -ENOMEM;
|
||||
arr[n_arr++] = gr->gr_gid;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(arr);
|
||||
return n_arr;
|
||||
}
|
||||
|
||||
static size_t getgr_buffer_size(void) {
|
||||
long bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
return bufsize <= 0 ? 4096U : (size_t) bufsize;
|
||||
|
||||
@@ -185,6 +185,11 @@ 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 getpwuid_malloc(uid_t uid, struct passwd **ret);
|
||||
int getpwnam_malloc(const char *name, struct passwd **ret);
|
||||
|
||||
@@ -596,4 +596,38 @@ TEST(lookup_grent_in_files) {
|
||||
ASSERT_STREQ(gr->gr_name, "testgroup1");
|
||||
}
|
||||
|
||||
TEST(lookup_groups_in_files) {
|
||||
_cleanup_(unlink_tempfilep) char fn[] = "/tmp/test-user-util-group-XXXXXX";
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
ASSERT_OK(fmkostemp_safe(fn, "w", &f));
|
||||
ASSERT_OK(write_string_stream(
|
||||
f,
|
||||
"testgroup1:x:100:testuser1,testuser2\n"
|
||||
"testgroup2:x:200:testuser1\n"
|
||||
"testgroup3:x:300:\n"
|
||||
"testgroup4:x:400:root,somebody,testuser1\n",
|
||||
/* flags= */ 0));
|
||||
ASSERT_OK(fflush_and_check(f));
|
||||
|
||||
char **files = STRV_MAKE(fn);
|
||||
|
||||
/* Lookup by name */
|
||||
_cleanup_free_ gid_t *arr = NULL;
|
||||
|
||||
ASSERT_EQ(lookup_groups_in_files(files, "testuser1", 100, &arr), 3);
|
||||
gid_t exp1[] = { 100, 200, 400 };
|
||||
ASSERT_EQ(memcmp(arr, exp1, sizeof(exp1)), 0);
|
||||
arr = mfree(arr);
|
||||
|
||||
ASSERT_EQ(lookup_groups_in_files(files, "testuser1", 0, &arr), 4);
|
||||
gid_t exp2[] = { 0, 100, 200, 400 };
|
||||
ASSERT_EQ(memcmp(arr, exp2, sizeof(exp2)), 0);
|
||||
arr = mfree(arr);
|
||||
|
||||
ASSERT_EQ(lookup_groups_in_files(files, "testuser3", 300, &arr), 1);
|
||||
gid_t exp3[] = { 300 };
|
||||
ASSERT_EQ(memcmp(arr, exp3, sizeof(exp3)), 0);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
||||
Reference in New Issue
Block a user