aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarel Kočí <cynerd@email.cz>2022-02-11 13:06:01 +0100
committerKarel Kočí <cynerd@email.cz>2022-02-11 13:06:01 +0100
commitdb9e7c9a30e9430119efb34ca9b5324314e6b4a8 (patch)
tree5a8d1978e779ff6b6b473efc0081eaf93b8961dd
parent8d61610974c4e60510358ce1bdb22c1042c465a9 (diff)
downloaduroot-db9e7c9a30e9430119efb34ca9b5324314e6b4a8.tar.gz
uroot-db9e7c9a30e9430119efb34ca9b5324314e6b4a8.tar.bz2
uroot-db9e7c9a30e9430119efb34ca9b5324314e6b4a8.zip
Read subuid and subgid files instead of hard coded values
This implements reading of /etc/subuid and /etc/subgid files to correctly map user and group IDs. It also allows just mapping the user itself if there is no mapping configured.
-rw-r--r--main.c4
-rw-r--r--utils.c53
-rw-r--r--utils.h9
3 files changed, 58 insertions, 8 deletions
diff --git a/main.c b/main.c
index 058aa3b..9ffaf6a 100644
--- a/main.c
+++ b/main.c
@@ -107,9 +107,9 @@ int main(int argc, char **argv) {
&chargs);
#define FAIL(MSG) do { fputs(MSG, stderr); kill(chpid, SIGKILL); return 1; } while (false);
- if (new_map_id("uid", chpid, getuid()))
+ if (new_map_id(MAP_ID_USER, chpid, getuid()))
FAIL("Mapping of uid failed!\n");
- if (new_map_id("gid", chpid, getgid()))
+ if (new_map_id(MAP_ID_GROUP, chpid, getgid()))
FAIL("Mapping of gid failed!\n");
sigpipe_signal(chargs.sigpipe);
diff --git a/utils.c b/utils.c
index e4f771d..e30b4db 100644
--- a/utils.c
+++ b/utils.c
@@ -24,6 +24,9 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
#include "utils.h"
#include "conf.h"
@@ -53,15 +56,57 @@ const char *get_shell() {
return ret;
}
-int new_map_id(const char *idtp, pid_t pid, int id) {
- // TODO check /etc/sub* for current user subids and map them
+struct subid {
+ char *start;
+ char *count;
+};
+
+struct subid parse_sub(const char *idtp, const char *name) {
+ FILE *f = fopen(aprintf("/etc/sub%s", idtp), "r");
+ struct subid res = {NULL, NULL};
+ char *line = NULL;
+ ssize_t len = 0;
+ while ((len = getline(&line, &len, f)) != -1) {
+ char *firstcol = strchr(line, ':');
+ if (firstcol == NULL || strncmp(name, line, firstcol - line))
+ continue;
+ char *seccol = strchr(firstcol + 1, ':');
+ if (seccol == NULL)
+ continue;
+ res.start = strndup(firstcol + 1, (seccol - firstcol) - 1);
+ res.count = strndup(seccol + 1, len - 1 - (seccol - line) - (line[len - 1] == '\n' ? 1 : 0));
+ }
+ free(line);
+ fclose(f);
+ return res;
+}
+
+int new_map_id(enum mapidtype type, pid_t pid, int id) {
+ // TODO possibly we should use all maps provided by sub* files for given
+ // account. It is common that there is only one mapping but there can
+ // technically be multiple ones.
+ char const *idtp;
+ struct subid subid;
+ switch (type) {
+ case MAP_ID_USER:
+ idtp = "uid";
+ struct passwd *upass = getpwuid(getuid());
+ subid = parse_sub(idtp, upass->pw_name);
+ break;
+ case MAP_ID_GROUP:
+ idtp = "gid";
+ struct group *gpass = getgrgid(getgid());
+ subid = parse_sub(idtp, gpass->gr_name);
+ break;
+ }
pid_t chld = fork();
if (!chld) {
char *tool = aprintf("new%smap", idtp);
char *const args[] = {
- tool, aprintf("%d", pid),
+ tool,
+ aprintf("%d", pid),
"0", aprintf("%d", id), "1",
- "1", "65537", "65536",
+ subid.start && subid.count ? "1" : NULL, subid.start, subid.count,
NULL
};
execvp(tool, args);
diff --git a/utils.h b/utils.h
index b9c943f..3a41956 100644
--- a/utils.h
+++ b/utils.h
@@ -35,7 +35,12 @@ char *printf_into(char *dst, const char *msg, ...) __attribute__((format(printf,
// returns path to shell interpreter
const char *get_shell();
-// call newuidmap and newgidmap for process of given pid
-int new_map_id(const char *idtp, pid_t pid, int id);
+enum mapidtype {
+ MAP_ID_USER,
+ MAP_ID_GROUP
+};
+
+// call newuidmap or newgidmap for process of given pid
+int new_map_id(enum mapidtype type, pid_t pid, int id);
#endif