id.c (6093B)
- // Collection of Unix tools, comparable to coreutils
- // SPDX-FileCopyrightText: 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
- // SPDX-License-Identifier: MPL-2.0
- #define _DEFAULT_SOURCE // getgrouplist (4.4BSD+)
- #include <grp.h> // getgrgid, getgroups, getgrouplist(glibc)
- #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*, getgrouplist(FreeBSD, NetBSD)
- bool name_flag = false;
- static int
- simple_list_groups(struct passwd *pw, int ngroups, gid_t *groups)
- {
- for(int i = 0; i < ngroups; i++)
- {
- if(name_flag)
- {
- struct group *lgr = getgrgid(groups[i]);
- if(lgr == NULL)
- {
- return 1;
- }
- int sep = ' ';
- if(i == ngroups - 1)
- {
- sep = '\n';
- }
- int ret = printf("%s%c", lgr->gr_name, sep);
- if(ret < 0)
- {
- return 1;
- }
- }
- else
- {
- int sep = ' ';
- if(i == ngroups - 1)
- {
- sep = '\n';
- }
- int ret = printf("%u%c", groups[i], sep);
- if(ret < 0)
- {
- return 1;
- }
- }
- }
- return 0;
- }
- static int
- list_groups(struct passwd *pw, int ngroups, gid_t *groups)
- {
- printf(" groups=");
- for(int i = 0; i < ngroups; i++)
- {
- struct group *lgr = getgrgid(groups[i]);
- if(name_flag)
- {
- if(lgr == NULL)
- {
- return 1;
- }
- int sep = ' ';
- if(i == ngroups - 1)
- {
- sep = '\0';
- }
- int ret = printf("%s%c", lgr->gr_name, sep);
- if(ret < 0)
- {
- return 1;
- }
- }
- else
- {
- int ret = printf("%u", groups[i]);
- if(ret < 0)
- {
- return 1;
- }
- if(lgr != NULL)
- {
- int ret = printf("(%s)", lgr->gr_name);
- if(ret < 0)
- {
- return 1;
- }
- }
- if(i != ngroups - 1)
- {
- printf(",");
- }
- }
- }
- return 0;
- }
- int
- print_gid(char *field, struct group *gr, gid_t gid)
- {
- if(gr && gr->gr_name)
- {
- if(name_flag)
- {
- return printf("%s=%s", field, gr->gr_name);
- }
- return printf("%s=%u(%s)", field, gid, gr->gr_name);
- }
- else
- {
- if(name_flag)
- {
- return -1;
- }
- return printf("%s=%u", field, gid);
- }
- }
- int
- print_uid(char *field, struct passwd *pw, uid_t uid)
- {
- if(pw && pw->pw_name)
- {
- if(name_flag)
- {
- return printf("%s=%s", field, pw->pw_name);
- }
- return printf("%s=%u(%s)", field, uid, pw->pw_name);
- }
- else
- {
- if(name_flag)
- {
- return -1;
- }
- return printf("%s=%u", field, 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 = 0, c = 0;
- 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();
- 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)
- {
- switch(c)
- {
- case 'G':
- mode = ID_GROUPS;
- break;
- case 'u':
- mode = ID_UID;
- break;
- case 'g':
- mode = ID_GID;
- break;
- case 'n':
- name_flag = true;
- break;
- case 'r':
- real_flag = true;
- break;
- default:
- usage();
- free(groups);
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
- if(argc == 0)
- {
- 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");
- goto failure;
- }
- }
- else if(argc == 1)
- {
- struct passwd *pw_n = getpwnam(argv[0]);
- if(pw_n == NULL)
- {
- goto failure;
- }
- pw = *pw_n;
- epw = *pw_n;
- uid = pw.pw_uid;
- 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");
- goto failure;
- }
- }
- else
- {
- usage();
- }
- struct group *gr = getgrgid(gid);
- struct group *egr = getgrgid(egid);
- if(mode == ID_GID)
- {
- if(!real_flag)
- {
- gid = egid;
- }
- if(!name_flag)
- {
- ret = printf("%u\n", gid);
- }
- else
- {
- if(gr == NULL || gr->gr_name == NULL)
- {
- ret--;
- fprintf(stderr, "id: cannot find name for group ID %u\n", gid);
- printf("%u\n", gid);
- }
- else
- {
- ret = printf("%s\n", gr->gr_name);
- }
- }
- if(ret < 0)
- {
- goto failure;
- }
- goto done;
- }
- if(mode == ID_UID)
- {
- if(!real_flag)
- {
- uid = euid;
- }
- if(!name_flag)
- {
- ret = printf("%u\n", uid);
- }
- else
- {
- if(pw.pw_name == NULL)
- {
- ret--;
- fprintf(stderr, "id: cannot find name for user ID %u\n", uid);
- printf("%u\n", uid);
- }
- else
- {
- ret = printf("%s\n", pw.pw_name);
- }
- }
- if(ret < 0)
- {
- goto failure;
- }
- goto done;
- }
- if(mode == ID_GROUPS)
- {
- if(real_flag)
- {
- ret = simple_list_groups(&pw, ngroups, groups);
- }
- else
- {
- ret = simple_list_groups(&epw, ngroups, groups);
- }
- if(ret != 0)
- {
- goto failure;
- }
- goto done;
- }
- ret = print_uid("uid", &pw, uid);
- if(ret < 0)
- {
- goto failure;
- }
- if(euid != uid)
- {
- ret = print_uid(" euid", &epw, euid);
- if(ret < 0)
- {
- goto failure;
- }
- }
- ret = print_gid(" gid", gr, gid);
- if(ret < 0)
- {
- goto failure;
- }
- if(egid != gid)
- {
- ret = print_gid(" egid", egr, egid);
- if(ret < 0)
- {
- goto failure;
- }
- }
- if(list_groups(&pw, ngroups, groups) != 0)
- {
- goto failure;
- }
- ret = printf("\n");
- if(ret < 0)
- {
- goto failure;
- }
- done:
- free(groups);
- return 0;
- failure:
- free(groups);
- return 1;
- }