commit: 15907c2898039d17ce812a712fccabfb8403a5e4
parent 0679a401e9ef76091c43c113828650b362736d16
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Mon, 14 Mar 2022 21:16:28 +0100
bin/id: Handle user argument
Diffstat:
M | bin/id.c | 166 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
M | test-bin/id | 21 | +++++++++++++++++++-- |
2 files changed, 120 insertions(+), 67 deletions(-)
diff --git a/bin/id.c b/bin/id.c
@@ -4,7 +4,6 @@
#define _DEFAULT_SOURCE // for getgrouplist
-#include <assert.h> // assert
#include <grp.h> // getgrgid, getgrouplist
#include <pwd.h> // getpwuid
#include <stdbool.h> // bool
@@ -28,6 +27,12 @@ simple_list_groups(struct passwd *pw)
// getgrouplist(3) BSD extension might not be in all Unixes
int grls = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+
+ if(grls < 0)
+ {
+ goto failure;
+ }
+
for(int i = 0; i < ngroups; i++)
{
if(name_flag)
@@ -152,8 +157,6 @@ print_gid(char *field, struct group *gr, gid_t gid)
{
if(gr && gr->gr_name)
{
- assert(gr->gr_gid == gid);
-
if(name_flag)
{
return printf("%s=%s", field, gr->gr_name);
@@ -177,8 +180,6 @@ print_uid(char *field, struct passwd *pw, uid_t uid)
{
if(pw && pw->pw_name)
{
- assert(pw->pw_uid == uid);
-
if(name_flag)
{
return printf("%s=%s", field, pw->pw_name);
@@ -197,14 +198,46 @@ print_uid(char *field, struct passwd *pw, uid_t uid)
}
}
+void
+safe_getpwuid(uid_t uid, struct passwd *res)
+{
+ struct passwd *pw = getpwuid(uid);
+
+ if(pw != NULL)
+ {
+ *res = *pw;
+ }
+}
+
+enum id_modes
+{
+ ID_NORMAL,
+ ID_GROUPS,
+ ID_GID,
+ ID_UID,
+};
+
+void
+usage()
+{
+ fprintf(stderr, "Usage: id [-Ggu] [-nr] [user]\n");
+}
+
int
main(int argc, char *argv[])
{
int ret, c;
- bool u_flag = false;
- bool G_flag = false;
- bool g_flag = false;
- bool real_flag = false;
+ enum id_modes mode = ID_NORMAL;
+ bool real_flag = false;
+
+ // geteuid, getuid, getegid, getgid shall always be successful
+ uid_t uid = getuid();
+ uid_t euid = geteuid();
+ gid_t gid = getgid();
+ gid_t egid = getegid();
+
+ struct passwd pw = {.pw_uid = uid, .pw_gid = gid};
+ struct passwd epw = {.pw_uid = euid, .pw_gid = egid};
/* flawfinder: ignore. Old implementations of getopt should fix themselves */
while((c = getopt(argc, argv, ":Ggunr")) != EOF)
@@ -212,39 +245,63 @@ main(int argc, char *argv[])
switch(c)
{
case 'G':
- G_flag = true;
- break;
- case 'n':
- name_flag = true;
+ mode = ID_GROUPS;
break;
case 'u':
- u_flag = true;
+ mode = ID_UID;
break;
case 'g':
- g_flag = true;
+ mode = ID_GID;
+ break;
+ case 'n':
+ name_flag = true;
break;
case 'r':
real_flag = true;
break;
default:
- assert(false);
+ usage();
+ return 1;
}
}
argc -= optind;
argv += optind;
- if(g_flag)
+ if(argc == 0)
{
- gid_t gid;
+ safe_getpwuid(uid, &pw);
+ safe_getpwuid(euid, &epw);
+ }
+ else if(argc == 1)
+ {
+ struct passwd *pw_n = getpwnam(argv[0]);
- if(real_flag)
+ if(pw_n == NULL)
{
- gid = getgid();
+ return 1;
}
- else
+ pw = *pw_n;
+ epw = *pw_n;
+
+ uid = pw.pw_uid;
+ euid = epw.pw_uid;
+ gid = pw.pw_gid;
+ egid = epw.pw_gid;
+ }
+ else
+ {
+ usage();
+ }
+
+ struct group *gr = getgrgid(gid);
+ struct group *egr = getgrgid(egid);
+
+ if(mode == ID_GID)
+ {
+ if(!real_flag)
{
- gid = getegid();
+ gid = egid;
}
if(!name_flag)
@@ -253,11 +310,14 @@ main(int argc, char *argv[])
}
else
{
- struct group *gr = getgrgid(gid);
-
- assert(gr->gr_gid == gid);
-
- ret = printf("%s\n", gr->gr_name);
+ if(gr != NULL)
+ {
+ ret = printf("%s\n", gr->gr_name);
+ }
+ else
+ {
+ return 1;
+ }
}
if(ret < 0)
@@ -268,17 +328,11 @@ main(int argc, char *argv[])
return 0;
}
- if(u_flag)
+ if(mode == ID_UID)
{
- uid_t uid;
-
- if(real_flag)
- {
- uid = getuid();
- }
- else
+ if(!real_flag)
{
- uid = geteuid();
+ uid = euid;
}
if(!name_flag)
@@ -287,11 +341,7 @@ main(int argc, char *argv[])
}
else
{
- struct passwd *pw = getpwuid(uid);
-
- assert(pw->pw_uid == uid);
-
- ret = printf("%s\n", pw->pw_name);
+ ret = printf("%s\n", pw.pw_name);
}
if(ret < 0)
@@ -302,24 +352,16 @@ main(int argc, char *argv[])
return 0;
}
- // geteuid, getuid, getegid, getgid shall always be successful
- uid_t uid = getuid();
- uid_t euid = geteuid();
- gid_t gid = getgid();
- gid_t egid = getegid();
-
- struct passwd *pw = getpwuid(uid);
- struct passwd *epw = getpwuid(euid);
- // can return NULL (ie. without /etc/passwd)
-
- if(G_flag)
+ if(mode == ID_GROUPS)
{
- if(!real_flag)
+ if(real_flag)
{
- pw = epw;
+ ret = simple_list_groups(&pw);
+ } else {
+ ret = simple_list_groups(&epw);
}
- if(pw != NULL && simple_list_groups(pw) != 0)
+ if(ret != 0)
{
goto failure;
}
@@ -327,7 +369,7 @@ main(int argc, char *argv[])
return 0;
}
- ret = print_uid("uid", pw, uid);
+ ret = print_uid("uid", &pw, uid);
if(ret < 0)
{
return 1;
@@ -335,22 +377,19 @@ main(int argc, char *argv[])
if(euid != uid)
{
- ret = print_uid(" euid", epw, euid);
+ ret = print_uid(" euid", &epw, euid);
if(ret < 0)
{
goto failure;
}
}
- struct group *gr = getgrgid(gid);
-
ret = print_gid(" gid", gr, gid);
if(ret < 0)
{
goto failure;
}
- struct group *egr = getgrgid(egid);
if(egid != gid)
{
ret = print_gid(" egid", egr, egid);
@@ -361,12 +400,9 @@ main(int argc, char *argv[])
}
}
- if(pw != NULL)
+ if(list_groups(&pw) != 0)
{
- if(list_groups(pw) != 0)
- {
- goto failure;
- }
+ goto failure;
}
ret = printf("\n");
diff --git a/test-bin/id b/test-bin/id
@@ -64,9 +64,9 @@ noetc_body() {
set -f
# shellcheck disable=SC2086
- atf_check -o "inline:uid=$(id -u) gid=$(id -g)\n" -- bwrap ${bwrap_args} ../bin/id
+ atf_check -o "inline:uid=$(id -u) gid=$(id -g) groups=$(id -g)\n" -- bwrap ${bwrap_args} ../bin/id
# shellcheck disable=SC2086
- atf_check -o "inline:uid=$(id -ur) gid=$(id -gr)\n" -- bwrap ${bwrap_args} ../bin/id -r
+ atf_check -o "inline:uid=$(id -ur) gid=$(id -gr) groups=$(id -g)\n" -- bwrap ${bwrap_args} ../bin/id -r
# shellcheck disable=SC2086
atf_check -s exit:1 -- bwrap ${bwrap_args} ../bin/id -n
@@ -103,12 +103,27 @@ nogroup_body() {
atf_check -o "inline:$(id -gr)\n" -- bwrap ${bwrap_args} ../bin/id -gr
}
+atf_test_case badarg
+badarg_body() {
+ atf_check -s exit:1 -e 'inline:Usage: id [-Ggu] [-nr] [user]\n' ../bin/id -a
+}
+
+atf_test_case root cleanup
+root_body() {
+ atf_check -o save:root.out ../bin/id root
+ atf_check grep -q "uid=$(id -u root)($(id -un root)) gid=$(id -g root)($(id -gn root)) groups=" root.out
+}
+root_cleanup() {
+ rm -f root.out
+}
+
atf_init_test_cases() {
cd "$(atf_get_srcdir)" || exit 1
. ../test_functions.sh
atf_add_test_case devfull
+ atf_add_test_case badarg
atf_add_test_case noargs
atf_add_test_case names
@@ -118,4 +133,6 @@ atf_init_test_cases() {
atf_add_test_case noetc
atf_add_test_case nogroup
+
+ atf_add_test_case root
}