logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git
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:

Mbin/id.c166++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mtest-bin/id21+++++++++++++++++++--
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 }