// id.c, version 0.1.1 // OMKOV coreutils implementation of POSIX id // Copyright (C) 2020, Jakob Wakeling // MIT Licence /* TODO Fix memory leak when listing supplementary groups (may be unfixable) */ #include "util/error.h" #include "util/optget.h" #include #include #include #include #include #include #include #include #define VERSION "0.1.1" typedef struct passwd pwd_t; typedef struct group grp_t; static struct lop lops[] = { { "help", ARG_NUL, 256 }, { "version", ARG_NUL, 257 }, { NULL, 0, 0 } }; static char mode; static bool nflag; static bool rflag; static inline void id(uid_t uid, uid_t euid, gid_t gid, gid_t egid); static inline void groups(const char *user, gid_t gid, gid_t egid); static void hlp(void); static void ver(void); int main(int ac, char *av[]) { A0 = av[0]; struct opt opt = OPTGET_INIT; opt.str = "Ggnru"; opt.lops = lops; for (int o; (o = optget(&opt, av, 1)) != -1;) switch (o) { case 'G': case 'g': case 'u': { if (mode) { error(1, "invalid option combination"); } else { mode = (char)o; } break; } case 'n': { nflag = true; break; } case 'r': { rflag = true; break; } case 256: { hlp(); return 0; } case 257: { ver(); return 0; } default: { return 1; } } if (!mode && (nflag || rflag)) { error(1, "options 'n' and 'r' require 'G', 'g', or 'u'"); } uid_t uid, euid; gid_t gid, egid; if (opt.ind == ac) { uid = getuid(); euid = geteuid(); gid = getgid(); egid = getegid(); id (uid, euid, gid, egid); } else for (char **p = &av[opt.ind]; *p; ++p) { pwd_t *pwd; if (!(pwd = getpwnam(*p))) { error(1, "%s: invalid user", *p); } uid = euid = pwd->pw_uid; gid = egid = pwd->pw_gid; id (uid, euid, gid, egid); } return 0; } static inline void id(uid_t uid, uid_t euid, gid_t gid, gid_t egid) { pwd_t *pwd; grp_t *grp; if (mode == 'G') { pwd = getpwuid(uid); groups(pwd->pw_name, gid, egid); } else if (mode == 'g') { grp = getgrgid(rflag ? gid : egid); nflag ? fputs(grp->gr_name, stdout) : printf("%u", grp->gr_gid); } else if (mode == 'u') { pwd = getpwuid(rflag ? uid : euid); nflag ? fputs(pwd->pw_name, stdout) : printf("%u", pwd->pw_uid); } else { pwd = getpwuid(uid); grp = getgrgid(gid); printf("uid=%u(%s) gid=%u(%s) ", uid, pwd->pw_name, gid, grp->gr_name); if (uid != euid) { pwd = getpwuid(euid); printf("euid=%u(%s) ", euid, pwd->pw_name); pwd = getpwuid(uid); } if (gid != egid) { grp = getgrgid(egid); printf("egid=%u(%s) ", egid, grp->gr_name); } fputs("groups=", stdout); groups(pwd->pw_name, gid, egid); } fputc('\n', stdout); return; } static inline void groups(const char *user, gid_t gid, gid_t egid) { grp_t *grp = getgrgid(gid); if (mode) { nflag ? fputs(grp->gr_name, stdout) : printf("%u", gid); } else { printf("%u(%s)", gid, grp->gr_name); } if (gid != egid) { grp = getgrgid(egid); if (mode) { nflag ? printf(" %s", grp->gr_name) : printf(" %u", egid); } else { printf(",%u(%s)", egid, grp->gr_name); } } setgrent(); while ((grp = getgrent()) != NULL) { if (grp->gr_gid == gid || grp->gr_gid == egid) { continue; } for (int i = 0; grp->gr_mem[i]; ++i) { if (strcmp(grp->gr_mem[i], user) == 0) { if (mode) { nflag ? printf(" %s", grp->gr_name) : printf(" %u", grp->gr_gid); } else { printf(",%u(%s)", grp->gr_gid, grp->gr_name); } } } } endgrent(); return; } static void hlp(void) { puts("id - return user identity\n"); puts("usage: id [-G|-g|-u] [-nr] [user...]\n"); puts("options:"); puts(" -G Output all group IDs"); puts(" -g Output only the effective group ID"); puts(" -n Output names of groups and users instead of their IDs"); puts(" -r Output the real ID instead of the effective ID"); puts(" -u Output only the effective user ID"); puts(" --help Display help information"); puts(" --version Display version information"); } static void ver(void) { puts("OMKOV coreutils id, version " VERSION); puts("Copyright (C) 2020, Jakob Wakeling"); puts("MIT Licence (https://opensource.org/licenses/MIT)"); }