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