From c663b1034a0569bee92ebcf1ac66cc0551614875 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 4 Jan 2020 13:48:55 +0100 Subject: [PATCH] su: Use setgroups() to switch over to the target user's extra GIDs Before this, su would leave the process's extra GIDs untouched, simply inheriting them from whoever spawned su. Now we grab the target user's groups from /etc/group and setgroups(). --- Userland/su.cpp | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Userland/su.cpp b/Userland/su.cpp index 8f7a10aa82..f600179b78 100644 --- a/Userland/su.cpp +++ b/Userland/su.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,8 +11,9 @@ int main(int argc, char** argv) { uid_t uid = 0; gid_t gid = 0; + struct passwd* pwd = nullptr; if (argc > 1) { - auto* pwd = getpwnam(argv[1]); + pwd = getpwnam(argv[1]); if (!pwd) { fprintf(stderr, "No such user: %s\n", argv[1]); return 1; @@ -19,7 +21,30 @@ int main(int argc, char** argv) uid = pwd->pw_uid; gid = pwd->pw_gid; } - int rc = setgid(uid); + + if (!pwd) + pwd = getpwuid(0); + + if (!pwd) { + fprintf(stderr, "No passwd entry.\n"); + return 1; + } + + Vector extra_gids; + for (auto* group = getgrent(); group; group = getgrent()) { + for (size_t i = 0; group->gr_mem[i]; ++i) { + if (!strcmp(pwd->pw_name, group->gr_mem[i])) + extra_gids.append(group->gr_gid); + } + } + endgrent(); + + int rc = setgroups(extra_gids.size(), extra_gids.data()); + if (rc < 0) { + perror("setgroups"); + return 1; + } + rc = setgid(uid); if (rc < 0) { perror("setgid"); return 1;