1181834Sroberto/*-
2181834Sroberto * Copyright (c) 1991, 1993
3181834Sroberto *	The Regents of the University of California.  All rights reserved.
4181834Sroberto *
5181834Sroberto * Redistribution and use in source and binary forms, with or without
6181834Sroberto * modification, are permitted provided that the following conditions
7181834Sroberto * are met:
8181834Sroberto * 1. Redistributions of source code must retain the above copyright
9181834Sroberto *    notice, this list of conditions and the following disclaimer.
10181834Sroberto * 2. Redistributions in binary form must reproduce the above copyright
11181834Sroberto *    notice, this list of conditions and the following disclaimer in the
12181834Sroberto *    documentation and/or other materials provided with the distribution.
13181834Sroberto * 3. Neither the name of the University nor the names of its contributors
14181834Sroberto *    may be used to endorse or promote products derived from this software
15280849Scy *    without specific prior written permission.
16181834Sroberto *
17181834Sroberto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18181834Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19181834Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20181834Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21181834Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22181834Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23181834Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24181834Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25181834Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26280849Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27181834Sroberto * SUCH DAMAGE.
28181834Sroberto */
29181834Sroberto
30181834Sroberto#include <sys/cdefs.h>
31181834Sroberto#ifndef lint
32181834Sroberto__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
33181834Sroberto The Regents of the University of California.  All rights reserved.");
34181834Sroberto#endif /* not lint */
35181834Sroberto
36181834Sroberto#ifndef lint
37181834Sroberto#if 0
38181834Srobertostatic char sccsid[] = "@(#)id.c	8.3 (Berkeley) 4/28/95";
39181834Sroberto#else
40181834Sroberto__RCSID("$NetBSD: id.c,v 1.31 2009/04/12 10:51:38 lukem Exp $");
41181834Sroberto#endif
42280849Scy#endif /* not lint */
43181834Sroberto
44181834Sroberto#include <sys/param.h>
45181834Sroberto
46181834Sroberto#include <err.h>
47181834Sroberto#include <errno.h>
48181834Sroberto#include <grp.h>
49181834Sroberto#include <pwd.h>
50181834Sroberto#include <stdio.h>
51181834Sroberto#include <stdlib.h>
52181834Sroberto#include <string.h>
53181834Sroberto#include <unistd.h>
54181834Sroberto
55181834Srobertostatic void current(void);
56181834Srobertostatic void pretty(struct passwd *);
57181834Srobertostatic void group(struct passwd *, int);
58280849Scy__dead static void usage(void);
59280849Scystatic void user(struct passwd *);
60280849Scystatic struct passwd *who(char *);
61181834Sroberto
62181834Srobertostatic int maxgroups;
63181834Srobertostatic gid_t *groups;
64181834Sroberto
65181834Srobertoint
66181834Srobertomain(int argc, char *argv[])
67181834Sroberto{
68181834Sroberto	struct group *gr;
69181834Sroberto	struct passwd *pw;
70181834Sroberto	int ch, id;
71181834Sroberto	int Gflag, gflag, nflag, pflag, rflag, uflag;
72181834Sroberto	const char *opts;
73181834Sroberto
74280849Scy	Gflag = gflag = nflag = pflag = rflag = uflag = 0;
75280849Scy
76280849Scy	if (strcmp(getprogname(), "groups") == 0) {
77280849Scy		Gflag = 1;
78280849Scy		nflag = 1;
79280849Scy		opts = "";
80280849Scy		if (argc > 2)
81280849Scy			usage();
82280849Scy	} else if (strcmp(getprogname(), "whoami") == 0) {
83280849Scy		uflag = 1;
84280849Scy		nflag = 1;
85280849Scy		opts = "";
86280849Scy		if (argc > 1)
87280849Scy			usage();
88280849Scy	} else
89181834Sroberto		opts = "Ggnpru";
90280849Scy
91280849Scy	while ((ch = getopt(argc, argv, opts)) != -1)
92280849Scy		switch (ch) {
93280849Scy		case 'G':
94280849Scy			Gflag = 1;
95280849Scy			break;
96280849Scy		case 'g':
97280849Scy			gflag = 1;
98280849Scy			break;
99280849Scy		case 'n':
100280849Scy			nflag = 1;
101181834Sroberto			break;
102280849Scy		case 'p':
103280849Scy			pflag = 1;
104280849Scy			break;
105280849Scy		case 'r':
106280849Scy			rflag = 1;
107280849Scy			break;
108280849Scy		case 'u':
109280849Scy			uflag = 1;
110280849Scy			break;
111280849Scy		case '?':
112181834Sroberto		default:
113280849Scy			usage();
114280849Scy		}
115280849Scy	argc -= optind;
116280849Scy	argv += optind;
117181834Sroberto
118280849Scy	switch (Gflag + gflag + pflag + uflag) {
119280849Scy	case 1:
120280849Scy		break;
121280849Scy	case 0:
122280849Scy		if (!nflag && !rflag)
123280849Scy			break;
124280849Scy		/* FALLTHROUGH */
125280849Scy	default:
126280849Scy		usage();
127280849Scy	}
128280849Scy
129280849Scy	if (strcmp(opts, "") != 0 && argc > 1)
130280849Scy		usage();
131280849Scy
132280849Scy	pw = *argv ? who(*argv) : NULL;
133280849Scy
134280849Scy	maxgroups = sysconf(_SC_NGROUPS_MAX);
135280849Scy	if ((groups = malloc((maxgroups + 1) * sizeof(gid_t))) == NULL)
136280849Scy		err(1, NULL);
137181834Sroberto
138280849Scy	if (gflag) {
139280849Scy		id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
140280849Scy		if (nflag && (gr = getgrgid(id)))
141280849Scy			(void)printf("%s\n", gr->gr_name);
142280849Scy		else
143280849Scy			(void)printf("%u\n", id);
144280849Scy		goto done;
145280849Scy	}
146280849Scy
147280849Scy	if (uflag) {
148280849Scy		id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
149280849Scy		if (nflag && (pw = getpwuid(id)))
150280849Scy			(void)printf("%s\n", pw->pw_name);
151280849Scy		else
152280849Scy			(void)printf("%u\n", id);
153280849Scy		goto done;
154280849Scy	}
155181834Sroberto
156280849Scy	if (Gflag) {
157280849Scy		group(pw, nflag);
158280849Scy		goto done;
159280849Scy	}
160280849Scy
161280849Scy	if (pflag) {
162280849Scy		pretty(pw);
163280849Scy		goto done;
164280849Scy	}
165280849Scy
166280849Scy	if (pw)
167280849Scy		user(pw);
168280849Scy	else
169280849Scy		current();
170280849Scydone:
171280849Scy	free(groups);
172280849Scy
173280849Scy	return 0;
174280849Scy}
175280849Scy
176280849Scystatic void
177280849Scypretty(struct passwd *pw)
178280849Scy{
179280849Scy	struct group *gr;
180280849Scy	u_int eid, rid;
181280849Scy	char *login;
182280849Scy
183280849Scy	if (pw) {
184280849Scy		(void)printf("uid\t%s\n", pw->pw_name);
185280849Scy		(void)printf("groups\t");
186280849Scy		group(pw, 1);
187280849Scy	} else {
188280849Scy		if ((login = getlogin()) == NULL)
189280849Scy			err(1, "getlogin");
190280849Scy
191280849Scy		pw = getpwuid(rid = getuid());
192280849Scy		if (pw == NULL || strcmp(login, pw->pw_name))
193280849Scy			(void)printf("login\t%s\n", login);
194280849Scy		if (pw)
195280849Scy			(void)printf("uid\t%s\n", pw->pw_name);
196280849Scy		else
197280849Scy			(void)printf("uid\t%u\n", rid);
198280849Scy
199280849Scy		if ((eid = geteuid()) != rid) {
200280849Scy			if ((pw = getpwuid(eid)) != NULL)
201280849Scy				(void)printf("euid\t%s\n", pw->pw_name);
202280849Scy			else
203280849Scy				(void)printf("euid\t%u\n", eid);
204280849Scy		}
205280849Scy		if ((rid = getgid()) != (eid = getegid())) {
206280849Scy			if ((gr = getgrgid(rid)) != NULL)
207280849Scy				(void)printf("rgid\t%s\n", gr->gr_name);
208280849Scy			else
209280849Scy				(void)printf("rgid\t%u\n", rid);
210280849Scy		}
211280849Scy		(void)printf("groups\t");
212280849Scy		group(NULL, 1);
213280849Scy	}
214280849Scy}
215280849Scy
216280849Scystatic void
217280849Scycurrent(void)
218280849Scy{
219280849Scy	struct group *gr;
220280849Scy	struct passwd *pw;
221280849Scy	gid_t gid, egid, lastid;
222280849Scy	uid_t uid, euid;
223280849Scy	int cnt, ngroups;
224280849Scy	const char *fmt;
225280849Scy
226280849Scy	uid = getuid();
227280849Scy	(void)printf("uid=%ju", (uintmax_t)uid);
228280849Scy	if ((pw = getpwuid(uid)) != NULL)
229280849Scy		(void)printf("(%s)", pw->pw_name);
230280849Scy	gid = getgid();
231280849Scy	(void)printf(" gid=%ju", (uintmax_t)gid);
232280849Scy	if ((gr = getgrgid(gid)) != NULL)
233280849Scy		(void)printf("(%s)", gr->gr_name);
234280849Scy	if ((euid = geteuid()) != uid) {
235280849Scy		(void)printf(" euid=%ju", (uintmax_t)euid);
236280849Scy		if ((pw = getpwuid(euid)) != NULL)
237280849Scy			(void)printf("(%s)", pw->pw_name);
238280849Scy	}
239280849Scy	if ((egid = getegid()) != gid) {
240280849Scy		(void)printf(" egid=%ju", (uintmax_t)egid);
241280849Scy		if ((gr = getgrgid(egid)) != NULL)
242280849Scy			(void)printf("(%s)", gr->gr_name);
243280849Scy	}
244280849Scy	if ((ngroups = getgroups(maxgroups, groups)) != 0) {
245280849Scy		for (fmt = " groups=%ju", lastid = -1, cnt = 0; cnt < ngroups;
246280849Scy		    fmt = ",%ju", lastid = gid, cnt++) {
247280849Scy			gid = groups[cnt];
248280849Scy			if (lastid == gid)
249280849Scy				continue;
250280849Scy			(void)printf(fmt, (uintmax_t)gid);
251280849Scy			if ((gr = getgrgid(gid)) != NULL)
252280849Scy				(void)printf("(%s)", gr->gr_name);
253280849Scy		}
254280849Scy	}
255280849Scy	(void)printf("\n");
256280849Scy}
257280849Scy
258280849Scystatic void
259280849Scyuser(struct passwd *pw)
260280849Scy{
261280849Scy	struct group *gr;
262280849Scy	const char *fmt;
263280849Scy	int cnt, id, lastid, ngroups;
264280849Scy	gid_t *glist = groups;
265280849Scy
266280849Scy	id = pw->pw_uid;
267280849Scy	(void)printf("uid=%u(%s)", id, pw->pw_name);
268280849Scy	(void)printf(" gid=%lu", (u_long)pw->pw_gid);
269280849Scy	if ((gr = getgrgid(pw->pw_gid)) != NULL)
270280849Scy		(void)printf("(%s)", gr->gr_name);
271280849Scy	ngroups = maxgroups + 1;
272280849Scy	if (getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups) == -1) {
273280849Scy		glist = malloc(ngroups * sizeof(gid_t));
274280849Scy		(void) getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups);
275280849Scy	}
276280849Scy	for (fmt = " groups=%u", lastid = -1, cnt = 0; cnt < ngroups;
277280849Scy	    fmt=",%u", lastid = id, cnt++) {
278280849Scy		id = glist[cnt];
279280849Scy		if (lastid == id)
280280849Scy			continue;
281280849Scy		(void)printf(fmt, id);
282280849Scy		if ((gr = getgrgid(id)) != NULL)
283280849Scy			(void)printf("(%s)", gr->gr_name);
284280849Scy	}
285280849Scy	(void)printf("\n");
286280849Scy	if (glist != groups)
287280849Scy		free(glist);
288280849Scy}
289280849Scy
290280849Scystatic void
291280849Scygroup(struct passwd *pw, int nflag)
292280849Scy{
293280849Scy	struct group *gr;
294280849Scy	int cnt, ngroups;
295280849Scy	gid_t id, lastid;
296280849Scy	const char *fmt;
297280849Scy	gid_t *glist = groups;
298280849Scy
299280849Scy	if (pw) {
300280849Scy		ngroups = maxgroups;
301280849Scy		if (getgrouplist(pw->pw_name, pw->pw_gid, glist, &ngroups)
302280849Scy		    == -1) {
303280849Scy			glist = malloc(ngroups * sizeof(gid_t));
304280849Scy			(void) getgrouplist(pw->pw_name, pw->pw_gid, glist,
305280849Scy					    &ngroups);
306280849Scy		}
307280849Scy	} else {
308280849Scy		glist[0] = getgid();
309280849Scy		ngroups = getgroups(maxgroups, glist + 1) + 1;
310280849Scy	}
311280849Scy	fmt = nflag ? "%s" : "%u";
312280849Scy	for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
313280849Scy		if (lastid == (id = glist[cnt]) || (cnt && id == glist[0]))
314280849Scy			continue;
315280849Scy		if (nflag) {
316280849Scy			if ((gr = getgrgid(id)) != NULL)
317280849Scy				(void)printf(fmt, gr->gr_name);
318280849Scy			else
319280849Scy				(void)printf(*fmt == ' ' ? " %u" : "%u",
320280849Scy				    id);
321280849Scy			fmt = " %s";
322280849Scy		} else {
323280849Scy			(void)printf(fmt, id);
324280849Scy			fmt = " %u";
325280849Scy		}
326280849Scy		lastid = id;
327280849Scy	}
328285169Scy	(void)printf("\n");
329285169Scy	if (glist != groups)
330285169Scy		free(glist);
331280849Scy}
332280849Scy
333280849Scystatic struct passwd *
334280849Scywho(char *u)
335280849Scy{
336280849Scy	struct passwd *pw;
337280849Scy	long id;
338280849Scy	char *ep;
339280849Scy
340280849Scy	/*
341280849Scy	 * Translate user argument into a pw pointer.  First, try to
342280849Scy	 * get it as specified.  If that fails, try it as a number.
343280849Scy	 */
344280849Scy	if ((pw = getpwnam(u)) != NULL)
345280849Scy		return pw;
346280849Scy	id = strtol(u, &ep, 10);
347280849Scy	if (*u && !*ep && (pw = getpwuid(id)))
348280849Scy		return pw;
349280849Scy	errx(1, "%s: No such user", u);
350280849Scy	/* NOTREACHED */
351280849Scy	return NULL;
352280849Scy}
353280849Scy
354280849Scystatic void
355280849Scyusage(void)
356280849Scy{
357280849Scy
358280849Scy	if (strcmp(getprogname(), "groups") == 0) {
359280849Scy		(void)fprintf(stderr, "usage: groups [user]\n");
360280849Scy	} else if (strcmp(getprogname(), "whoami") == 0) {
361280849Scy		(void)fprintf(stderr, "usage: whoami\n");
362280849Scy	} else {
363280849Scy		(void)fprintf(stderr, "usage: id [user]\n");
364280849Scy		(void)fprintf(stderr, "       id -G [-n] [user]\n");
365280849Scy		(void)fprintf(stderr, "       id -g [-nr] [user]\n");
366280849Scy		(void)fprintf(stderr, "       id -p [user]\n");
367280849Scy		(void)fprintf(stderr, "       id -u [-nr] [user]\n");
368280849Scy	}
369280849Scy	exit(1);
370280849Scy}
371280849Scy