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().
This commit is contained in:
Andreas Kling 2020-01-04 13:48:55 +01:00
commit c663b1034a
Notes: sideshowbarker 2024-07-19 10:22:29 +09:00

View file

@ -1,3 +1,4 @@
#include <AK/Vector.h>
#include <alloca.h>
#include <grp.h>
#include <pwd.h>
@ -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<gid_t> 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;