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
main(int argc,char * argv[])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
usage()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
puid(uid_t uid)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
pgid(gid_t gid)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
prid(TYPE how,uid_t id)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 */
getusergroups(gidsetsize,grouplist,user,prgid)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