util: add virGetSubUIDs

A function for parsing /etc/sub[ug]id

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
Ján Tomko 2023-12-13 12:51:43 +01:00
parent 42edb10f17
commit 2ef4be0a3e
5 changed files with 121 additions and 0 deletions

View File

@ -3641,6 +3641,7 @@ virGetHostname;
virGetHostnameQuiet;
virGetPassword;
virGetSelfLastChanged;
virGetSubIDs;
virGetSystemPageSize;
virGetSystemPageSizeKB;
virGetUserCacheDirectory;
@ -3671,6 +3672,7 @@ virSetNonBlock;
virSetSockReuseAddr;
virSetUIDGID;
virSetUIDGIDWithCaps;
virSubIDsFree;
virUpdateSelfLastChanged;
virValidateWWN;
virWaitForDevices;

View File

@ -1086,6 +1086,76 @@ virGetGroupName(gid_t gid G_GNUC_UNUSED)
}
#endif /* WITH_GETPWUID_R */
void
virSubIDsFree(virSubID **uids, size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
if ((*uids)[i].idstr)
g_free((*uids)[i].idstr);
}
g_clear_pointer(uids, g_free);
}
int
virGetSubIDs(virSubID **retval, const char *file)
{
g_autofree char *buf = NULL;
g_auto(GStrv) lines = NULL;
virSubID *entries = NULL;
size_t i = 0;
size_t len;
int ret = -1;
*retval = NULL;
if (virFileReadAll(file, BUFSIZ, &buf) < 0)
return -1;
lines = g_strsplit(buf, "\n", 0);
if (!lines)
return -1;
len = g_strv_length(lines);
entries = g_new0(virSubID, len);
for (i = 0; i < len; i++) {
g_auto(GStrv) fields = NULL;
unsigned long ulong_id;
fields = g_strsplit(lines[i], ":", 0);
if (!fields)
goto cleanup;
if (g_strv_length(fields) != 3)
break;
if (g_ascii_isdigit(fields[0][0])) {
if (virStrToLong_ul(fields[0], NULL, 10, &ulong_id) < 0)
goto cleanup;
entries[i].id = ulong_id;
} else {
entries[i].idstr = g_strdup(fields[0]);
}
if (virStrToLong_ul(fields[1], NULL, 10, &ulong_id) < 0)
goto cleanup;
entries[i].start = ulong_id;
if (virStrToLong_ul(fields[2], NULL, 10, &ulong_id) < 0)
goto cleanup;
entries[i].range = ulong_id;
}
*retval = g_steal_pointer(&entries);
ret = i;
cleanup:
if (entries)
virSubIDsFree(&entries, len);
return ret;
}
#if WITH_CAPNG
/* Set the real and effective uid and gid to the given values, while
* maintaining the capabilities indicated by bits in @capBits. Return

View File

@ -102,6 +102,18 @@ char *virGetUserName(uid_t uid) G_NO_INLINE;
char *virGetGroupName(gid_t gid) G_NO_INLINE;
int virGetGroupList(uid_t uid, gid_t group, gid_t **groups)
ATTRIBUTE_NONNULL(3);
typedef struct _virSubID {
uid_t id;
char *idstr;
uid_t start;
uid_t range;
} virSubID;
int virGetSubIDs(virSubID **ret, const char *file);
void virSubIDsFree(virSubID **uids, size_t n);
int virGetUserID(const char *name,
uid_t *uid) G_GNUC_WARN_UNUSED_RESULT;
int virGetGroupID(const char *name,

View File

@ -377,6 +377,38 @@ testKernelCmdlineMatchParam(const void *data G_GNUC_UNUSED)
}
static int
testGetSubIDs(const void *data G_GNUC_UNUSED)
{
g_autofree char *subuid_file = g_strdup_printf("%s/virutiltestdata/subuid", abs_srcdir);
virSubID *subids = NULL;
int len = 0;
int ret = -1;
if ((len = virGetSubIDs(&subids, subuid_file)) < 0) {
VIR_TEST_DEBUG("virGetSubIDs failed");
goto cleanup;
}
if (len != 4) {
VIR_TEST_DEBUG("virGetSubIDs returned %d (expected 4)", len);
goto cleanup;
}
if (STRNEQ(subids[0].idstr, "joe")) {
VIR_TEST_DEBUG("virGetSubIDs returned wrong name for entry 0: '%s'", NULLSTR(subids[0].idstr));
goto cleanup;
}
ret = 0;
cleanup:
if (len >= 0)
virSubIDsFree(&subids, len);
return ret;
}
static int
mymain(void)
{
@ -400,6 +432,7 @@ mymain(void)
DO_TEST(OverflowCheckMacro);
DO_TEST(KernelCmdlineNextParam);
DO_TEST(KernelCmdlineMatchParam);
DO_TEST(GetSubIDs);
return result == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@ -0,0 +1,4 @@
joe:100000:65535
bob:300000:65535
1024:400000:65535
alice:200000:65535