diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 31c0f169c3..6efaf3114d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3641,6 +3641,7 @@ virGetHostname; virGetHostnameQuiet; virGetPassword; virGetSelfLastChanged; +virGetSubIDs; virGetSystemPageSize; virGetSystemPageSizeKB; virGetUserCacheDirectory; @@ -3671,6 +3672,7 @@ virSetNonBlock; virSetSockReuseAddr; virSetUIDGID; virSetUIDGIDWithCaps; +virSubIDsFree; virUpdateSelfLastChanged; virValidateWWN; virWaitForDevices; diff --git a/src/util/virutil.c b/src/util/virutil.c index 17d65ad834..bd3bbe3f0d 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -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 diff --git a/src/util/virutil.h b/src/util/virutil.h index ab8511bf8d..3bac15d02b 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -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, diff --git a/tests/utiltest.c b/tests/utiltest.c index 5930557c08..b30bfbed70 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -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; } diff --git a/tests/virutiltestdata/subuid b/tests/virutiltestdata/subuid new file mode 100644 index 0000000000..c873c0e3bf --- /dev/null +++ b/tests/virutiltestdata/subuid @@ -0,0 +1,4 @@ +joe:100000:65535 +bob:300000:65535 +1024:400000:65535 +alice:200000:65535