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