1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 29 /* All Rights Reserved */ 30 31 32 #include <locale.h> 33 #include <stdio.h> 34 #include <pwd.h> 35 #include <grp.h> 36 #include <sys/param.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <project.h> 40 #include <stdlib.h> 41 #include <alloca.h> 42 43 #define PWNULL ((struct passwd *)0) 44 #define GRNULL ((struct group *)0) 45 46 typedef enum TYPE { 47 UID, EUID, GID, EGID, SGID 48 } TYPE; 49 50 typedef enum PRINT { 51 CURR, /* Print uid/gid only */ 52 ALLGROUPS, /* Print all groups */ 53 GROUP, /* Print only group */ 54 USER /* Print only uid */ 55 } PRINT; 56 static PRINT mode = CURR; 57 58 static int usage(void); 59 static void puid(uid_t); 60 static void pgid(gid_t); 61 static void prid(TYPE, uid_t); 62 static int getusergroups(int, gid_t *, char *, gid_t); 63 64 static int nflag = 0; /* Output names, not numbers */ 65 static int rflag = 0; /* Output real, not effective IDs */ 66 static char stdbuf[BUFSIZ]; 67 68 int 69 main(int argc, char *argv[]) 70 { 71 gid_t *idp; 72 uid_t uid, euid; 73 gid_t gid, egid, prgid; 74 int c, aflag = 0, project_flag = 0; 75 struct passwd *pwp; 76 int i, j; 77 int groupmax = sysconf(_SC_NGROUPS_MAX); 78 gid_t *groupids = alloca(groupmax * sizeof (gid_t)); 79 struct group *gr; 80 char *user = NULL; 81 82 (void) setlocale(LC_ALL, ""); 83 84 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 85 #define TEXT_DOMAIN "SYS_TEST" 86 #endif 87 (void) textdomain(TEXT_DOMAIN); 88 while ((c = getopt(argc, argv, "Ggunarp")) != EOF) { 89 switch (c) { 90 case 'G': 91 if (mode != CURR) 92 return (usage()); 93 mode = ALLGROUPS; 94 break; 95 96 case 'g': 97 if (mode != CURR) 98 return (usage()); 99 mode = GROUP; 100 break; 101 102 case 'a': 103 aflag++; 104 break; 105 106 case 'n': 107 nflag++; 108 break; 109 110 case 'r': 111 rflag++; 112 break; 113 114 case 'u': 115 if (mode != CURR) 116 return (usage()); 117 mode = USER; 118 break; 119 120 case 'p': 121 if (mode != CURR) 122 return (usage()); 123 project_flag++; 124 break; 125 126 case '?': 127 return (usage()); 128 } 129 } 130 setbuf(stdout, stdbuf); 131 argc -= optind-1; 132 argv += optind-1; 133 134 /* -n and -r must be combined with one of -[Ggu] */ 135 /* -r cannot be combined with -G */ 136 /* -a and -p cannot be combined with -[Ggu] */ 137 138 if ((mode == CURR && (nflag || rflag)) || 139 (mode == ALLGROUPS && rflag) || 140 (argc != 1 && argc != 2) || 141 (mode != CURR && (project_flag || aflag))) 142 return (usage()); 143 if (argc == 2) { 144 if ((pwp = getpwnam(argv[1])) == PWNULL) { 145 (void) fprintf(stderr, 146 gettext("id: invalid user name: \"%s\"\n"), 147 argv[1]); 148 return (1); 149 } 150 user = argv[1]; 151 uid = euid = pwp->pw_uid; 152 prgid = gid = egid = pwp->pw_gid; 153 } else { 154 uid = getuid(); 155 gid = getgid(); 156 euid = geteuid(); 157 egid = getegid(); 158 } 159 160 if (mode != CURR) { 161 if (!rflag) { 162 uid = euid; 163 gid = egid; 164 } 165 if (mode == USER) 166 puid(uid); 167 else if (mode == GROUP) 168 pgid(gid); 169 else if (mode == ALLGROUPS) { 170 pgid(gid); 171 if (user) 172 i = getusergroups(groupmax, groupids, user, 173 prgid); 174 else 175 i = getgroups(groupmax, groupids); 176 if (i == -1) 177 perror("getgroups"); 178 else if (i > 0) { 179 for (j = 0; j < i; ++j) { 180 if ((gid = groupids[j]) == egid) 181 continue; 182 (void) putchar(' '); 183 pgid(gid); 184 } 185 } 186 } 187 (void) putchar('\n'); 188 } else { 189 prid(UID, uid); 190 prid(GID, gid); 191 if (uid != euid) 192 prid(EUID, euid); 193 if (gid != egid) 194 prid(EGID, egid); 195 196 if (aflag) { 197 if (user) 198 i = getusergroups(groupmax, groupids, user, 199 prgid); 200 else 201 i = getgroups(groupmax, groupids); 202 if (i == -1) 203 perror("getgroups"); 204 else if (i > 0) { 205 (void) printf(" groups="); 206 for (idp = groupids; i--; idp++) { 207 (void) printf("%u", *idp); 208 if (gr = getgrgid(*idp)) 209 (void) printf("(%s)", 210 gr->gr_name); 211 if (i) 212 (void) putchar(','); 213 } 214 } 215 } 216 #ifdef XPG4 217 /* 218 * POSIX requires us to show all supplementary groups 219 * groups other than the effective group already listed. 220 * 221 * This differs from -a above, because -a always shows 222 * all groups including the effective group in the group= 223 * line. 224 * 225 * It would be simpler if SunOS could just adopt this 226 * POSIX behavior, as it is so incredibly close to the 227 * the norm already. 228 * 229 * Then the magic -a flag could just indicate whether or 230 * not we are suppressing the effective group id. 231 */ 232 else { 233 if (user) 234 i = getusergroups(groupmax, groupids, user, 235 prgid); 236 else 237 i = getgroups(groupmax, groupids); 238 if (i == -1) 239 perror("getgroups"); 240 else if (i > 1) { 241 (void) printf(" groups="); 242 for (idp = groupids; i--; idp++) { 243 if (*idp == egid) 244 continue; 245 (void) printf("%u", *idp); 246 if (gr = getgrgid(*idp)) 247 (void) printf("(%s)", 248 gr->gr_name); 249 if (i) 250 (void) putchar(','); 251 } 252 } 253 } 254 #endif 255 if (project_flag) { 256 struct project proj; 257 void *projbuf; 258 projid_t curprojid = getprojid(); 259 260 if ((projbuf = malloc(PROJECT_BUFSZ)) == NULL) { 261 (void) fprintf(stderr, "unable to allocate " 262 "memory\n"); 263 return (2); 264 } 265 266 if (user) { 267 if (getdefaultproj(user, &proj, projbuf, 268 PROJECT_BUFSZ) != NULL) 269 (void) printf(" projid=%d(%s)", 270 (int)proj.pj_projid, proj.pj_name); 271 else 272 /* 273 * This can only happen if project 274 * "default" has been removed from 275 * /etc/project file or the whole 276 * project database file was removed. 277 */ 278 (void) printf(" projid=(NONE)"); 279 } else { 280 if (getprojbyid(curprojid, &proj, projbuf, 281 PROJECT_BUFSZ) == NULL) 282 (void) printf(" projid=%d", 283 (int)curprojid); 284 else 285 (void) printf(" projid=%d(%s)", 286 (int)curprojid, proj.pj_name); 287 } 288 free(projbuf); 289 } 290 (void) putchar('\n'); 291 } 292 return (0); 293 } 294 295 static int 296 usage() 297 { 298 (void) fprintf(stderr, gettext( 299 "Usage: id [-ap] [user]\n" 300 " id -G [-n] [user]\n" 301 " id -g [-nr] [user]\n" 302 " id -u [-nr] [user]\n")); 303 return (2); 304 } 305 306 static void 307 puid(uid_t uid) 308 { 309 struct passwd *pw; 310 311 if (nflag && (pw = getpwuid(uid)) != PWNULL) 312 (void) printf("%s", pw->pw_name); 313 else 314 (void) printf("%u", uid); 315 } 316 317 static void 318 pgid(gid_t gid) 319 { 320 struct group *gr; 321 322 if (nflag && (gr = getgrgid(gid)) != GRNULL) 323 (void) printf("%s", gr->gr_name); 324 else 325 (void) printf("%u", gid); 326 } 327 328 static void 329 prid(TYPE how, uid_t id) 330 { 331 char *s; 332 333 switch ((int)how) { 334 case UID: 335 s = "uid"; 336 break; 337 338 case EUID: 339 s = " euid"; 340 break; 341 342 case GID: 343 s = " gid"; 344 break; 345 346 case EGID: 347 s = " egid"; 348 break; 349 350 } 351 if (s != NULL) 352 (void) printf("%s=", s); 353 (void) printf("%u", id); 354 switch ((int)how) { 355 case UID: 356 case EUID: 357 { 358 struct passwd *pwp; 359 360 if ((pwp = getpwuid(id)) != PWNULL) 361 (void) printf("(%s)", pwp->pw_name); 362 363 } 364 break; 365 case GID: 366 case EGID: 367 { 368 struct group *grp; 369 370 if ((grp = getgrgid(id)) != GRNULL) 371 (void) printf("(%s)", grp->gr_name); 372 } 373 break; 374 } 375 } 376 377 /* 378 * Get the supplementary group affiliation for the user 379 */ 380 static int getusergroups(gidsetsize, grouplist, user, prgid) 381 int gidsetsize; 382 gid_t *grouplist; 383 char *user; 384 gid_t prgid; 385 { 386 struct group *group; 387 char **gr_mem; 388 int ngroups = 0; 389 390 setgrent(); 391 while ((ngroups < gidsetsize) && ((group = getgrent()) != NULL)) 392 for (gr_mem = group->gr_mem; *gr_mem; gr_mem++) 393 if (strcmp(user, *gr_mem) == 0) { 394 if (gidsetsize) 395 grouplist[ngroups] = group->gr_gid; 396 ngroups++; 397 } 398 endgrent(); 399 if (gidsetsize && !ngroups) 400 grouplist[ngroups++] = prgid; 401 return (ngroups); 402 } 403