]> git.ipfire.org Git - people/ms/pakfire.git/commitdiff
pakfire: Parse SUBUID/GIDs from /etc/sub{u,g}id
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 11 Aug 2022 17:00:14 +0000 (17:00 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 11 Aug 2022 17:00:14 +0000 (17:00 +0000)
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 <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/pwd.h
src/libpakfire/jail.c
src/libpakfire/pakfire.c
src/libpakfire/pwd.c

index de9e729e8850d0ddb8cebeff4ad71b668bb644e1..bdf09573b7e716235ec7fa7b5af5fce944990457 100644 (file)
 #include <grp.h>
 #include <pwd.h>
 
+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 */
index 18bca5e09b41c945902fef09c8f8f697384347b9..2f9adcb12ef4f2c457be27fb16a475adba6204f1 100644 (file)
@@ -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;
 }
index a6e5c8de6e930938e046c17284424e0a3e6cd6a7..d05972657bf05e69685715663afb6a6092830485 100644 (file)
@@ -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)
index c05d2a82330efb3370ceb4bb9965a7fd6c4f8318..0a4df711649fd7f29e74dd4bf20467244592a989 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <pakfire/logging.h>
 #include <pakfire/pakfire.h>
 #include <pakfire/pwd.h>
+#include <pakfire/util.h>
+
+#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;
+}