commit: bb481deac770083524b18577724cfa21b2061d78
parent f9298dca270a060cc63c1c9d9024186bffa171b2
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 20 Oct 2022 21:21:38 +0200
cmd/id: Fix only returning runtime groups from current user
Diffstat:
M | cmd/id.c | 166 | ++++++++++++++++++++++++++++++++++++------------------------------------------- |
M | test-cmd/id | 10 | ++++++++++ |
2 files changed, 85 insertions(+), 91 deletions(-)
diff --git a/cmd/id.c b/cmd/id.c
@@ -3,35 +3,20 @@
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
#define _POSIX_C_SOURCE 200809L
-#include <grp.h> // getgrgid, getgroups
-#include <pwd.h> // getpwuid
-#include <stdbool.h> // bool
-#include <stdio.h> // printf, perror
-#include <stdlib.h> // malloc, free
-#include <sys/types.h> // uid_t
-#include <unistd.h> // getuid, getgid, getopt, opt*
+#define _DEFAULT_SOURCE // getgrouplist
+#include <grp.h> // getgrgid, getgroups, getgrouplist
+#include <pwd.h> // getpwuid
+#include <stdbool.h> // bool
+#include <stdio.h> // printf, perror
+#include <stdlib.h> // malloc, free
+#include <sys/types.h> // uid_t
+#include <unistd.h> // getuid, getgid, getopt, opt*
bool name_flag = false;
static int
-simple_list_groups(struct passwd *pw)
+simple_list_groups(struct passwd *pw, int ngroups, gid_t *groups)
{
- int ngroups_max = (int)sysconf(_SC_NGROUPS_MAX) + 1;
- gid_t *groups = malloc(sizeof(gid_t) * ngroups_max);
- if(groups == NULL)
- {
- perror("groups malloc");
- return 1;
- }
-
- int ngroups = getgroups(ngroups_max, groups);
-
- if(ngroups < 0)
- {
- perror("getgroups");
- goto failure;
- }
-
for(int i = 0; i < ngroups; i++)
{
if(name_flag)
@@ -39,7 +24,7 @@ simple_list_groups(struct passwd *pw)
struct group *lgr = getgrgid(groups[i]);
if(lgr == NULL)
{
- goto failure;
+ return 1;
}
int sep = ' ';
@@ -51,7 +36,7 @@ simple_list_groups(struct passwd *pw)
int ret = printf("%s%c", lgr->gr_name, sep);
if(ret < 0)
{
- goto failure;
+ return 1;
}
}
else
@@ -65,95 +50,67 @@ simple_list_groups(struct passwd *pw)
int ret = printf("%u%c", groups[i], sep);
if(ret < 0)
{
- goto failure;
+ return 1;
}
}
}
- free(groups);
return 0;
-
-failure:
- free(groups);
- return 1;
}
static int
-list_groups(struct passwd *pw)
+list_groups(struct passwd *pw, int ngroups, gid_t *groups)
{
- int ngroups_max = (int)sysconf(_SC_NGROUPS_MAX) + 1;
- gid_t *groups = malloc(sizeof(gid_t) * ngroups_max);
- if(groups == NULL)
- {
- perror("groups malloc");
- return 1;
- }
+ printf(" groups=");
- int ngroups = getgroups(ngroups_max, groups);
-
- if(ngroups < 0)
- {
- perror("getgroups");
- goto failure;
- }
- else
+ for(int i = 0; i < ngroups; i++)
{
- printf(" groups=");
+ struct group *lgr = getgrgid(groups[i]);
- for(int i = 0; i < ngroups; i++)
+ if(name_flag)
{
- struct group *lgr = getgrgid(groups[i]);
-
- if(name_flag)
+ if(lgr == NULL)
{
- if(lgr == NULL)
- {
- goto failure;
- }
+ return 1;
+ }
- int sep = ' ';
- if(i == ngroups - 1)
- {
- sep = '\0';
- }
+ int sep = ' ';
+ if(i == ngroups - 1)
+ {
+ sep = '\0';
+ }
- int ret = printf("%s%c", lgr->gr_name, sep);
- if(ret < 0)
- {
- goto failure;
- }
+ int ret = printf("%s%c", lgr->gr_name, sep);
+ if(ret < 0)
+ {
+ return 1;
}
- else
+ }
+ else
+ {
+ int ret = printf("%u", groups[i]);
+ if(ret < 0)
{
- int ret = printf("%u", groups[i]);
- if(ret < 0)
- {
- goto failure;
- }
+ return 1;
+ }
- if(lgr != NULL)
+ if(lgr != NULL)
+ {
+ int ret = printf("(%s)", lgr->gr_name);
+ if(ret < 0)
{
- int ret = printf("(%s)", lgr->gr_name);
- if(ret < 0)
- {
- goto failure;
- }
+ return 1;
}
+ }
- if(i != ngroups - 1)
- {
- printf(",");
- }
+ if(i != ngroups - 1)
+ {
+ printf(",");
}
}
}
- free(groups);
return 0;
-
-failure:
- free(groups);
- return 1;
}
int
@@ -234,6 +191,15 @@ main(int argc, char *argv[])
enum id_modes mode = ID_NORMAL;
bool real_flag = false;
+ int ngroups = 0;
+ int ngroups_max = (int)sysconf(_SC_NGROUPS_MAX) + 1;
+ gid_t *groups = malloc(sizeof(gid_t) * ngroups_max);
+ if(groups == NULL)
+ {
+ perror("groups malloc");
+ return 1;
+ }
+
// geteuid, getuid, getegid, getgid shall always be successful
uid_t uid = getuid();
uid_t euid = geteuid();
@@ -276,6 +242,14 @@ main(int argc, char *argv[])
{
safe_getpwuid(uid, &pw);
safe_getpwuid(euid, &epw);
+
+ // Get groups from currently running process instead of configuration
+ ngroups = getgroups(ngroups_max, groups);
+ if(ngroups < 0)
+ {
+ perror("getgroups");
+ return 1;
+ }
}
else if(argc == 1)
{
@@ -292,6 +266,14 @@ main(int argc, char *argv[])
euid = epw.pw_uid;
gid = pw.pw_gid;
egid = epw.pw_gid;
+
+ // Can only get groups from configuration
+ ngroups = getgrouplist(pw.pw_name, pw.pw_gid, groups, &ngroups_max);
+ if(ngroups < 0)
+ {
+ perror("getgrouplist");
+ return 1;
+ }
}
else
{
@@ -371,11 +353,11 @@ main(int argc, char *argv[])
{
if(real_flag)
{
- ret = simple_list_groups(&pw);
+ ret = simple_list_groups(&pw, ngroups, groups);
}
else
{
- ret = simple_list_groups(&epw);
+ ret = simple_list_groups(&epw, ngroups, groups);
}
if(ret != 0)
@@ -417,7 +399,7 @@ main(int argc, char *argv[])
}
}
- if(list_groups(&pw) != 0)
+ if(list_groups(&pw, ngroups, groups) != 0)
{
goto failure;
}
@@ -428,9 +410,11 @@ main(int argc, char *argv[])
return 1;
}
+ free(groups);
return 0;
failure:
printf("\n");
+ free(groups);
return 1;
}
diff --git a/test-cmd/id b/test-cmd/id
@@ -58,6 +58,16 @@ groups_body() {
atf_check -o not-empty ../cmd/id -Gnr
}
+# Make sure the correct list is returned for different users
+# Previously it would only return the runtime list of the current user
+atf_test_case regression_groups
+regression_groups() {
+ atf_check -o "not-inline:$(../cmd/id -G root)" ../cmd/id -G nobody
+ atf_check -o "not-inline:$(../cmd/id -Gr root)" ../cmd/id -Gr nobody
+ atf_check -o "not-inline:$(../cmd/id -Gn root)" ../cmd/id -Gn nobody
+ atf_check -o "not-inline:$(../cmd/id -Gnr root)" ../cmd/id -Gnr nobody
+}
+
atf_test_case noetc
noetc_body() {
bwrap_args="--bind / / --bind /var/empty /etc"