From 41c76557a0032ed1ce24e0cf2e4c31818629093d Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 11 Aug 2022 17:00:14 +0000 Subject: [PATCH] pakfire: Parse SUBUID/GIDs from /etc/sub{u,g}id This isn't particularly pretty but there does not seem to be a better solution integrated into glibc/nss/etc., yet. Signed-off-by: Michael Tremer --- src/libpakfire/include/pakfire/pwd.h | 16 ++ src/libpakfire/jail.c | 2 + src/libpakfire/pakfire.c | 33 +++- src/libpakfire/pwd.c | 226 +++++++++++++++++++++++++++ 4 files changed, 275 insertions(+), 2 deletions(-) diff --git a/src/libpakfire/include/pakfire/pwd.h b/src/libpakfire/include/pakfire/pwd.h index de9e729e..bdf09573 100644 --- a/src/libpakfire/include/pakfire/pwd.h +++ b/src/libpakfire/include/pakfire/pwd.h @@ -26,6 +26,17 @@ #include #include +struct pakfire_subuid { + char name[NAME_MAX]; + uid_t uid; + size_t length; +}; + +struct pakfire_subgid { + char name[NAME_MAX]; + gid_t gid; + size_t length; +}; struct passwd* pakfire_getpwnam(struct pakfire* pakfire, const char* name); struct passwd* pakfire_getpwuid(struct pakfire* pakfire, uid_t uid); @@ -33,6 +44,11 @@ struct passwd* pakfire_getpwuid(struct pakfire* pakfire, uid_t uid); struct group* pakfire_getgrnam(struct pakfire* pakfire, const char* name); struct group* pakfire_getgrgid(struct pakfire* pakfire, gid_t gid); +int pakfire_getsubuid(struct pakfire* pakfire, const uid_t uid, + struct pakfire_subuid* subuid); +int pakfire_getsubgid(struct pakfire* pakfire, const gid_t gid, + struct pakfire_subgid* subgid); + #endif #endif /* PAKFIRE_PWD_H */ diff --git a/src/libpakfire/jail.c b/src/libpakfire/jail.c index 18bca5e0..2f9adcb1 100644 --- a/src/libpakfire/jail.c +++ b/src/libpakfire/jail.c @@ -1388,9 +1388,11 @@ ERROR: pakfire_jail_close_pipe(jail, ctx.pipes.log_ERROR); pakfire_jail_close_pipe(jail, ctx.pipes.log_DEBUG); +#if 0 // Umount everything if (!pakfire_on_root(jail->pakfire)) pakfire_umount_all(jail->pakfire); +#endif return exit; } diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index a6e5c8de..d0597265 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -74,12 +74,19 @@ struct pakfire { char arch[ARCH_MAX]; char keystore_path[PATH_MAX]; - uid_t uid; int flags; // Lock FILE* lock; + // UID/GID of running user + uid_t uid; + gid_t gid; + + // Mapped UID/GID + struct pakfire_subuid subuid; + struct pakfire_subgid subgid; + // Pool Pool* pool; @@ -626,8 +633,9 @@ PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, const char* path, p->nrefs = 1; p->flags = flags; - // Store the UID we are running as + // Store the UID/GID we are running as p->uid = getuid(); + p->gid = getgid(); // Set architecture pakfire_string_set(p->arch, arch); @@ -693,6 +701,27 @@ PAKFIRE_EXPORT int pakfire_create(struct pakfire** pakfire, const char* path, } } + // Fetch sub UID/GIDs + if (p->uid) { + // UID + r = pakfire_getsubuid(p, p->uid, &p->subuid); + if (r) { + ERROR(p, "Could not fetch subuid: %m\n"); + goto ERROR; + } + + // GID + r = pakfire_getsubgid(p, p->gid, &p->subgid); + if (r) { + ERROR(p, "Could not fetch subgid: %m\n"); + goto ERROR; + } + + // Log + DEBUG(p, " subuid = %u - %zu\n", p->subuid.uid, p->subuid.uid + p->subuid.length); + DEBUG(p, " subgid = %u - %zu\n", p->subgid.gid, p->subgid.gid + p->subgid.length); + } + // Perform some safety checks r = pakfire_safety_checks(p); if (r) diff --git a/src/libpakfire/pwd.c b/src/libpakfire/pwd.c index c05d2a82..0a4df711 100644 --- a/src/libpakfire/pwd.c +++ b/src/libpakfire/pwd.c @@ -24,8 +24,13 @@ #include #include +#include #include #include +#include + +#define ETC_SUBUID "/etc/subuid" +#define ETC_SUBGID "/etc/subgid" static struct passwd* pakfire_getpwent(struct pakfire* pakfire, int(*cmp)(struct passwd* entry, const void* value), const void* value) { @@ -146,3 +151,224 @@ static int __pakfire_getgrgid(struct group* entry, const void* value) { struct group* pakfire_getgrgid(struct pakfire* pakfire, gid_t gid) { return pakfire_getgrent(pakfire, __pakfire_getgrgid, &gid); } + +// SUBUID/SUBGID + +static struct pakfire_subuid __pakfire_subuid; +static struct pakfire_subgid __pakfire_subgid; + +static struct pakfire_subuid* pakfire_fgetsubuid(struct pakfire* pakfire, FILE* f) { + int r; + + char* line = NULL; + size_t length = 0; + char* p = NULL; + + // Read the next line + while (1) { + r = getline(&line, &length, f); + if (r < 0) + goto ERROR; + + // Try reading the next line if this one was empty + else if (r == 0) + continue; + + // Fall through + else + break; + } + + // Reset r + r = 0; + + int i = 0; + + char* token = strtok_r(line, ":", &p); + while (token) { + switch (i++) { + // First field has the name + case 0: + pakfire_string_set(__pakfire_subuid.name, token); + break; + + // Second field has the UID + case 1: + __pakfire_subuid.uid = strtoul(token, NULL, 10); + break; + + // Third field has the length + case 2: + __pakfire_subuid.length = strtoul(token, NULL, 10); + break; + } + + token = strtok_r(NULL, ":", &p); + } + +ERROR: + if (line) + free(line); + + if (r) + return NULL; + + DEBUG(pakfire, "Parsed SUBUID entry: name=%s, subuid=%d, length=%zu\n", + __pakfire_subuid.name, __pakfire_subuid.uid, __pakfire_subuid.length); + + return &__pakfire_subuid; +} + +int pakfire_getsubuid(struct pakfire* pakfire, const uid_t uid, + struct pakfire_subuid* subuid) { + struct pakfire_subuid* entry = NULL; + int r = 1; + + // Fetch information about the running user + struct passwd* passwd = getpwuid(uid); + if (!passwd) { + ERROR(pakfire, "Could not fetch passwd entry for UID %d: %m\n", uid); + return 1; + } + + DEBUG(pakfire, "Fetching SUBUID for %s (%d)\n", passwd->pw_name, uid); + + // Open /etc/subuid + FILE* f = fopen(ETC_SUBUID, "r"); + if (!f) { + ERROR(pakfire, "Could not open %s: %m\n", ETC_SUBUID); + goto ERROR; + } + + // Walk through all entries + while (1) { + entry = pakfire_fgetsubuid(pakfire, f); + if (!entry) + break; + + // TODO Check if name matches UID + + // Check for match + if (strcmp(entry->name, passwd->pw_name) == 0) { + subuid->uid = entry->uid; + subuid->length = entry->length; + r = 0; + + break; + } + } + +ERROR: + if (f) + fclose(f); + + return r; +} + +static struct pakfire_subgid* pakfire_fgetsubgid(struct pakfire* pakfire, FILE* f) { + int r; + + char* line = NULL; + size_t length = 0; + char* p = NULL; + + // Read the next line + while (1) { + r = getline(&line, &length, f); + if (r < 0) + goto ERROR; + + // Try reading the next line if this one was empty + else if (r == 0) + continue; + + // Fall through + else + break; + } + + // Reset r + r = 0; + + int i = 0; + + char* token = strtok_r(line, ":", &p); + while (token) { + switch (i++) { + // First field has the name + case 0: + pakfire_string_set(__pakfire_subgid.name, token); + break; + + // Second field has the GID + case 1: + __pakfire_subgid.gid = strtoul(token, NULL, 10); + break; + + // Third field has the length + case 2: + __pakfire_subgid.length = strtoul(token, NULL, 10); + break; + } + + token = strtok_r(NULL, ":", &p); + } + +ERROR: + if (line) + free(line); + + if (r) + return NULL; + + DEBUG(pakfire, "Parsed SUBGID entry: name=%s, subgid=%d, length=%zu\n", + __pakfire_subgid.name, __pakfire_subgid.gid, __pakfire_subgid.length); + + return &__pakfire_subgid; +} + +int pakfire_getsubgid(struct pakfire* pakfire, const gid_t gid, + struct pakfire_subgid* subgid) { + struct pakfire_subgid* entry = NULL; + int r = 1; + + // Fetch information about the running user + struct group* group = getgrgid(gid); + if (!group) { + ERROR(pakfire, "Could not fetch group entry for GID %d: %m\n", gid); + return 1; + } + + DEBUG(pakfire, "Fetching SUBGID for %s (%d)\n", group->gr_name, gid); + + // Open /etc/subgid + FILE* f = fopen(ETC_SUBGID, "r"); + if (!f) { + ERROR(pakfire, "Could not open %s: %m\n", ETC_SUBGID); + goto ERROR; + } + + // Walk through all entries + while (1) { + entry = pakfire_fgetsubgid(pakfire, f); + if (!entry) + break; + + // TODO Check if name matches GID + + // Check for match + if (strcmp(entry->name, group->gr_name) == 0) { + subgid->gid = entry->gid; + subgid->length = entry->length; + r = 0; + + break; + } + } + +ERROR: + if (f) + fclose(f); + + return r; +} -- 2.47.3