1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31#ifndef lint
32__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
33 The Regents of the University of California.  All rights reserved.");
34#endif /* not lint */
35
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)id.c	8.3 (Berkeley) 4/28/95";
39#else
40__RCSID("$NetBSD: id.c,v 1.31 2009/04/12 10:51:38 lukem Exp $");
41#endif
42#endif /* not lint */
43
44#include <sys/param.h>
45
46#include <err.h>
47#include <errno.h>
48#include <grp.h>
49#include <pwd.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55static void current(void);
56static void pretty(struct passwd *);
57static void group(struct passwd *, int);
58__dead static void usage(void);
59static void user(struct passwd *);
60static struct passwd *who(char *);
61
62static int maxgroups;
63static gid_t *groups;
64
65int
66main(int argc, char *argv[])
67{
68	struct group *gr;
69	struct passwd *pw;
70	int ch, id;
71	int Gflag, gflag, nflag, pflag, rflag, uflag;
72	const char *opts;
73
74	Gflag = gflag = nflag = pflag = rflag = uflag = 0;
75
76	if (strcmp(getprogname(), "groups") == 0) {
77		Gflag = 1;
78		nflag = 1;
79		opts = "";
80		if (argc > 2)
81			usage();
82	} else if (strcmp(getprogname(), "whoami") == 0) {
83		uflag = 1;
84		nflag = 1;
85		opts = "";
86		if (argc > 1)
87			usage();
88	} else
89		opts = "Ggnpru";
90
91	while ((ch = getopt(argc, argv, opts)) != -1)
92		switch (ch) {
93		case 'G':
94			Gflag = 1;
95			break;
96		case 'g':
97			gflag = 1;
98			break;
99		case 'n':
100			nflag = 1;
101			break;
102		case 'p':
103			pflag = 1;
104			break;
105		case 'r':
106			rflag = 1;
107			break;
108		case 'u':
109			uflag = 1;
110			break;
111		case '?':
112		default:
113			usage();
114		}
115	argc -= optind;
116	argv += optind;
117
118	switch (Gflag + gflag + pflag + uflag) {
119	case 1:
120		break;
121	case 0:
122		if (!nflag && !rflag)
123			break;
124		/* FALLTHROUGH */
125	default:
126		usage();
127	}
128
129	if (strcmp(opts, "") != 0 && argc > 1)
130		usage();
131
132	pw = *argv ? who(*argv) : NULL;
133
134	maxgroups = sysconf(_SC_NGROUPS_MAX);
135	if ((groups = malloc((maxgroups + 1) * sizeof(gid_t))) == NULL)
136		err(1, NULL);
137
138	if (gflag) {
139		id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
140		if (nflag && (gr = getgrgid(id)))
141			(void)printf("%s\n", gr->gr_name);
142		else
143			(void)printf("%u\n", id);
144		goto done;
145	}
146
147	if (uflag) {
148		id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
149		if (nflag && (pw = getpwuid(id)))
150			(void)printf("%s\n", pw->pw_name);
151		else
152			(void)printf("%u\n", id);
153		goto done;
154	}
155
156	if (Gflag) {
157		group(pw, nflag);
158		goto done;
159	}
160
161	if (pflag) {
162		pretty(pw);
163		goto done;
164	}
165
166	if (pw)
167		user(pw);
168	else
169		current();
170done:
171	free(groups);
172
173	return 0;
174}
175
176static void
177pretty(struct passwd *pw)
178{
179	struct group *gr;
180	u_int eid, rid;
181	char *login;
182
183	if (pw) {
184		(void)printf("uid\t%s\n", pw->pw_name);
185		(void)printf("groups\t");
186		group(pw, 1);
187	} else {
188		if ((login = getlogin()) == NULL)
189			err(1, "getlogin");
190
191		pw = getpwuid(rid = getuid());
192		if (pw == NULL || strcmp(login, pw->pw_name))
193			(void)printf("login\t%s\n", login);
194		if (pw)
195			(void)printf("uid\t%s\n", pw->pw_name);
196		else
197			(void)printf("uid\t%u\n", rid);
198
199		if ((eid = geteuid()) != rid) {
200			if ((pw = getpwuid(eid)) != NULL)
201				(void)printf("euid\t%s\n", pw->pw_name);
202			else
203				(void)printf("euid\t%u\n", eid);
204		}
205		if ((rid = getgid()) != (eid = getegid())) {
206			if ((gr = getgrgid(rid)) != NULL)
207				(void)printf("rgid\t%s\n", gr->gr_name);
208			else
209				(void)printf("rgid\t%u\n", rid);
210		}
211		(void)printf("groups\t");
212		group(NULL, 1);
213	}
214}
215
216static void
217current(void)
218{
219	struct group *gr;
220	struct passwd *pw;
221	gid_t gid, egid, lastid;
222	uid_t uid, euid;
223	int cnt, ngroups;
224	const char *fmt;
225
226	uid = getuid();
227	(void)printf("uid=%ju", (uintmax_t)uid);
228	if ((pw = getpwuid(uid)) != NULL)
229		(void)printf("(%s)", pw->pw_name);
230	gid = getgid();
231	(void)printf(" gid=%ju", (uintmax_t)gid);
232	if ((gr = getgrgid(gid)) != NULL)
233		(void)printf("(%s)", gr->gr_name);
234	if ((euid = geteuid()) != uid) {
235		(void)printf(" euid=%ju", (uintmax_t)euid);
236		if ((pw = getpwuid(euid)) != NULL)
237			(void)printf("(%s)", pw->pw_name);
238	}
239	if ((egid = getegid()) != gid) {
240		(void)printf(" egid=%ju", (uintmax_t)egid);
241		if ((gr = getgrgid(egid)) != NULL)
242			(void)printf("(%s)", gr->gr_name);
243	}
244	if ((ngroups = getgroups(maxgroups, groups)) != 0) {
245		for (fmt = " groups=%ju", lastid = -1, cnt = 0; cnt < ngroups;
246		    fmt = ",%ju", lastid = gid, cnt++) {
247			gid = groups[cnt];
248			if (lastid == gid)
249				continue;
250			(void)printf(fmt, (uintmax_t)gid);
251			if ((gr = getgrgid(gid)) != NULL)
252				(void)printf("(%s)", gr->gr_name);
253		}
254	}
255	(void)printf("\n");
256}
257
258static void
259user(struct passwd *pw)
260{
261	struct group *gr;
262	const char *fmt;
263	int cnt, id, lastid, ngroups;
264	gid_t *glist = groups;
265
266	id = pw->pw_uid;
267	(void)printf("uid=%u(%s)", id, pw->pw_name);
268	(void)printf(" gid=%lu", (u_long)pw->pw_gid);
269	if ((gr = getgrgid(pw->pw_gid)) != NULL)
270		(void)printf("(%s)", gr->gr_name);
271	ngroups = maxgroups + 1;
272	if (getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups) == -1) {
273		glist = malloc(ngroups * sizeof(gid_t));
274		(void) getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups);
275	}
276	for (fmt = " groups=%u", lastid = -1, cnt = 0; cnt < ngroups;
277	    fmt=",%u", lastid = id, cnt++) {
278		id = glist[cnt];
279		if (lastid == id)
280			continue;
281		(void)printf(fmt, id);
282		if ((gr = getgrgid(id)) != NULL)
283			(void)printf("(%s)", gr->gr_name);
284	}
285	(void)printf("\n");
286	if (glist != groups)
287		free(glist);
288}
289
290static void
291group(struct passwd *pw, int nflag)
292{
293	struct group *gr;
294	int cnt, ngroups;
295	gid_t id, lastid;
296	const char *fmt;
297	gid_t *glist = groups;
298
299	if (pw) {
300		ngroups = maxgroups;
301		if (getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups)
302		    == -1) {
303			glist = malloc(ngroups * sizeof(gid_t));
304			(void) getgrouplist(pw->pw_name, pw->pw_gid, glist,
305					    &ngroups);
306		}
307	} else {
308		glist[0] = getgid();
309		ngroups = getgroups(maxgroups, glist + 1) + 1;
310	}
311	fmt = nflag ? "%s" : "%u";
312	for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
313		if (lastid == (id = glist[cnt]) || (cnt && id == glist[0]))
314			continue;
315		if (nflag) {
316			if ((gr = getgrgid(id)) != NULL)
317				(void)printf(fmt, gr->gr_name);
318			else
319				(void)printf(*fmt == ' ' ? " %u" : "%u",
320				    id);
321			fmt = " %s";
322		} else {
323			(void)printf(fmt, id);
324			fmt = " %u";
325		}
326		lastid = id;
327	}
328	(void)printf("\n");
329	if (glist != groups)
330		free(glist);
331}
332
333static struct passwd *
334who(char *u)
335{
336	struct passwd *pw;
337	long id;
338	char *ep;
339
340	/*
341	 * Translate user argument into a pw pointer.  First, try to
342	 * get it as specified.  If that fails, try it as a number.
343	 */
344	if ((pw = getpwnam(u)) != NULL)
345		return pw;
346	id = strtol(u, &ep, 10);
347	if (*u && !*ep && (pw = getpwuid(id)))
348		return pw;
349	errx(1, "%s: No such user", u);
350	/* NOTREACHED */
351	return NULL;
352}
353
354static void
355usage(void)
356{
357
358	if (strcmp(getprogname(), "groups") == 0) {
359		(void)fprintf(stderr, "usage: groups [user]\n");
360	} else if (strcmp(getprogname(), "whoami") == 0) {
361		(void)fprintf(stderr, "usage: whoami\n");
362	} else {
363		(void)fprintf(stderr, "usage: id [user]\n");
364		(void)fprintf(stderr, "       id -G [-n] [user]\n");
365		(void)fprintf(stderr, "       id -g [-nr] [user]\n");
366		(void)fprintf(stderr, "       id -p [user]\n");
367		(void)fprintf(stderr, "       id -u [-nr] [user]\n");
368	}
369	exit(1);
370}
371