| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| /* |
| * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ |
| /* All Rights Reserved */ |
| |
| |
| #include <locale.h> |
| #include <stdio.h> |
| #include <pwd.h> |
| #include <grp.h> |
| #include <sys/param.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <project.h> |
| #include <stdlib.h> |
| #include <alloca.h> |
| |
| #define PWNULL ((struct passwd *)0) |
| #define GRNULL ((struct group *)0) |
| |
| typedef enum TYPE { |
| UID, EUID, GID, EGID, SGID |
| } TYPE; |
| |
| typedef enum PRINT { |
| CURR, /* Print uid/gid only */ |
| ALLGROUPS, /* Print all groups */ |
| GROUP, /* Print only group */ |
| USER /* Print only uid */ |
| } PRINT; |
| static PRINT mode = CURR; |
| |
| static int usage(void); |
| static void puid(uid_t); |
| static void pgid(gid_t); |
| static void prid(TYPE, uid_t); |
| static int getusergroups(int, gid_t *, char *, gid_t); |
| |
| static int nflag = 0; /* Output names, not numbers */ |
| static int rflag = 0; /* Output real, not effective IDs */ |
| static char stdbuf[BUFSIZ]; |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| gid_t *idp; |
| uid_t uid, euid; |
| gid_t gid, egid, prgid; |
| int c, aflag = 0, project_flag = 0; |
| struct passwd *pwp; |
| int i, j; |
| int groupmax = sysconf(_SC_NGROUPS_MAX); |
| gid_t *groupids = alloca(groupmax * sizeof (gid_t)); |
| struct group *gr; |
| char *user = NULL; |
| |
| (void) setlocale(LC_ALL, ""); |
| |
| #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ |
| #define TEXT_DOMAIN "SYS_TEST" |
| #endif |
| (void) textdomain(TEXT_DOMAIN); |
| while ((c = getopt(argc, argv, "Ggunarp")) != EOF) { |
| switch (c) { |
| case 'G': |
| if (mode != CURR) |
| return (usage()); |
| mode = ALLGROUPS; |
| break; |
| |
| case 'g': |
| if (mode != CURR) |
| return (usage()); |
| mode = GROUP; |
| break; |
| |
| case 'a': |
| aflag++; |
| break; |
| |
| case 'n': |
| nflag++; |
| break; |
| |
| case 'r': |
| rflag++; |
| break; |
| |
| case 'u': |
| if (mode != CURR) |
| return (usage()); |
| mode = USER; |
| break; |
| |
| case 'p': |
| if (mode != CURR) |
| return (usage()); |
| project_flag++; |
| break; |
| |
| case '?': |
| return (usage()); |
| } |
| } |
| setbuf(stdout, stdbuf); |
| argc -= optind-1; |
| argv += optind-1; |
| |
| /* -n and -r must be combined with one of -[Ggu] */ |
| /* -r cannot be combined with -G */ |
| /* -a and -p cannot be combined with -[Ggu] */ |
| |
| if ((mode == CURR && (nflag || rflag)) || |
| (mode == ALLGROUPS && rflag) || |
| (argc != 1 && argc != 2) || |
| (mode != CURR && (project_flag || aflag))) |
| return (usage()); |
| if (argc == 2) { |
| if ((pwp = getpwnam(argv[1])) == PWNULL) { |
| (void) fprintf(stderr, |
| gettext("id: invalid user name: \"%s\"\n"), |
| argv[1]); |
| return (1); |
| } |
| user = argv[1]; |
| uid = euid = pwp->pw_uid; |
| prgid = gid = egid = pwp->pw_gid; |
| } else { |
| uid = getuid(); |
| gid = getgid(); |
| euid = geteuid(); |
| egid = getegid(); |
| } |
| |
| if (mode != CURR) { |
| if (!rflag) { |
| uid = euid; |
| gid = egid; |
| } |
| if (mode == USER) |
| puid(uid); |
| else if (mode == GROUP) |
| pgid(gid); |
| else if (mode == ALLGROUPS) { |
| pgid(gid); |
| if (user) |
| i = getusergroups(groupmax, groupids, user, |
| prgid); |
| else |
| i = getgroups(groupmax, groupids); |
| if (i == -1) |
| perror("getgroups"); |
| else if (i > 0) { |
| for (j = 0; j < i; ++j) { |
| if ((gid = groupids[j]) == egid) |
| continue; |
| (void) putchar(' '); |
| pgid(gid); |
| } |
| } |
| } |
| (void) putchar('\n'); |
| } else { |
| prid(UID, uid); |
| prid(GID, gid); |
| if (uid != euid) |
| prid(EUID, euid); |
| if (gid != egid) |
| prid(EGID, egid); |
| |
| if (aflag) { |
| if (user) |
| i = getusergroups(groupmax, groupids, user, |
| prgid); |
| else |
| i = getgroups(groupmax, groupids); |
| if (i == -1) |
| perror("getgroups"); |
| else if (i > 0) { |
| (void) printf(" groups="); |
| for (idp = groupids; i--; idp++) { |
| (void) printf("%u", *idp); |
| if (gr = getgrgid(*idp)) |
| (void) printf("(%s)", |
| gr->gr_name); |
| if (i) |
| (void) putchar(','); |
| } |
| } |
| } |
| #ifdef XPG4 |
| /* |
| * POSIX requires us to show all supplementary groups |
| * groups other than the effective group already listed. |
| * |
| * This differs from -a above, because -a always shows |
| * all groups including the effective group in the group= |
| * line. |
| * |
| * It would be simpler if SunOS could just adopt this |
| * POSIX behavior, as it is so incredibly close to the |
| * the norm already. |
| * |
| * Then the magic -a flag could just indicate whether or |
| * not we are suppressing the effective group id. |
| */ |
| else { |
| if (user) |
| i = getusergroups(groupmax, groupids, user, |
| prgid); |
| else |
| i = getgroups(groupmax, groupids); |
| if (i == -1) |
| perror("getgroups"); |
| else if (i > 1) { |
| (void) printf(" groups="); |
| for (idp = groupids; i--; idp++) { |
| if (*idp == egid) |
| continue; |
| (void) printf("%u", *idp); |
| if (gr = getgrgid(*idp)) |
| (void) printf("(%s)", |
| gr->gr_name); |
| if (i) |
| (void) putchar(','); |
| } |
| } |
| } |
| #endif |
| if (project_flag) { |
| struct project proj; |
| void *projbuf; |
| projid_t curprojid = getprojid(); |
| |
| if ((projbuf = malloc(PROJECT_BUFSZ)) == NULL) { |
| (void) fprintf(stderr, "unable to allocate " |
| "memory\n"); |
| return (2); |
| } |
| |
| if (user) { |
| if (getdefaultproj(user, &proj, projbuf, |
| PROJECT_BUFSZ) != NULL) |
| (void) printf(" projid=%d(%s)", |
| (int)proj.pj_projid, proj.pj_name); |
| else |
| /* |
| * This can only happen if project |
| * "default" has been removed from |
| * /etc/project file or the whole |
| * project database file was removed. |
| */ |
| (void) printf(" projid=(NONE)"); |
| } else { |
| if (getprojbyid(curprojid, &proj, projbuf, |
| PROJECT_BUFSZ) == NULL) |
| (void) printf(" projid=%d", |
| (int)curprojid); |
| else |
| (void) printf(" projid=%d(%s)", |
| (int)curprojid, proj.pj_name); |
| } |
| free(projbuf); |
| } |
| (void) putchar('\n'); |
| } |
| return (0); |
| } |
| |
| static int |
| usage() |
| { |
| (void) fprintf(stderr, gettext( |
| "Usage: id [-ap] [user]\n" |
| " id -G [-n] [user]\n" |
| " id -g [-nr] [user]\n" |
| " id -u [-nr] [user]\n")); |
| return (2); |
| } |
| |
| static void |
| puid(uid_t uid) |
| { |
| struct passwd *pw; |
| |
| if (nflag && (pw = getpwuid(uid)) != PWNULL) |
| (void) printf("%s", pw->pw_name); |
| else |
| (void) printf("%u", uid); |
| } |
| |
| static void |
| pgid(gid_t gid) |
| { |
| struct group *gr; |
| |
| if (nflag && (gr = getgrgid(gid)) != GRNULL) |
| (void) printf("%s", gr->gr_name); |
| else |
| (void) printf("%u", gid); |
| } |
| |
| static void |
| prid(TYPE how, uid_t id) |
| { |
| char *s; |
| |
| switch ((int)how) { |
| case UID: |
| s = "uid"; |
| break; |
| |
| case EUID: |
| s = " euid"; |
| break; |
| |
| case GID: |
| s = " gid"; |
| break; |
| |
| case EGID: |
| s = " egid"; |
| break; |
| |
| } |
| if (s != NULL) |
| (void) printf("%s=", s); |
| (void) printf("%u", id); |
| switch ((int)how) { |
| case UID: |
| case EUID: |
| { |
| struct passwd *pwp; |
| |
| if ((pwp = getpwuid(id)) != PWNULL) |
| (void) printf("(%s)", pwp->pw_name); |
| |
| } |
| break; |
| case GID: |
| case EGID: |
| { |
| struct group *grp; |
| |
| if ((grp = getgrgid(id)) != GRNULL) |
| (void) printf("(%s)", grp->gr_name); |
| } |
| break; |
| } |
| } |
| |
| /* |
| * Get the supplementary group affiliation for the user |
| */ |
| static int getusergroups(gidsetsize, grouplist, user, prgid) |
| int gidsetsize; |
| gid_t *grouplist; |
| char *user; |
| gid_t prgid; |
| { |
| struct group *group; |
| char **gr_mem; |
| int ngroups = 0; |
| |
| setgrent(); |
| while ((ngroups < gidsetsize) && ((group = getgrent()) != NULL)) |
| for (gr_mem = group->gr_mem; *gr_mem; gr_mem++) |
| if (strcmp(user, *gr_mem) == 0) { |
| if (gidsetsize) |
| grouplist[ngroups] = group->gr_gid; |
| ngroups++; |
| } |
| endgrent(); |
| if (gidsetsize && !ngroups) |
| grouplist[ngroups++] = prgid; |
| return (ngroups); |
| } |