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. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static const char copyright[] =
36"@(#) Copyright (c) 1991, 1993\n\
37	The Regents of the University of California.  All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41#if 0
42static char sccsid[] = "@(#)id.c	8.2 (Berkeley) 2/16/94";
43#endif
44#endif /* not lint */
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: src/usr.bin/id/id.c,v 1.33 2006/12/29 12:28:34 stefanf Exp $");
47
48#include <sys/param.h>
49#ifndef __APPLE__
50#include <sys/mac.h>
51#endif /* !__APPLE__ */
52
53#ifdef USE_BSM_AUDIT
54#include <bsm/audit.h>
55#endif
56
57#include <err.h>
58#include <errno.h>
59#include <grp.h>
60#include <pwd.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64#include <unistd.h>
65
66void	id_print(struct passwd *, int, int, int);
67void	pline(struct passwd *);
68void	pretty(struct passwd *);
69void	auditid(void);
70void	group(struct passwd *, int);
71void	maclabel(void);
72void	usage(void);
73struct passwd *who(char *);
74
75int isgroups, iswhoami;
76
77#ifdef __APPLE__
78// SPI for 5235093
79int32_t getgrouplist_2(const char *, gid_t, gid_t **);
80#endif
81
82int
83main(int argc, char *argv[])
84{
85	struct group *gr;
86	struct passwd *pw;
87	int Gflag, Mflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag;
88	int Aflag;
89	const char *myname;
90
91	Gflag = Mflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0;
92	Aflag = 0;
93
94	myname = strrchr(argv[0], '/');
95	myname = (myname != NULL) ? myname + 1 : argv[0];
96	if (strcmp(myname, "groups") == 0) {
97		isgroups = 1;
98		Gflag = nflag = 1;
99	}
100	else if (strcmp(myname, "whoami") == 0) {
101		iswhoami = 1;
102		uflag = nflag = 1;
103	}
104
105	while ((ch = getopt(argc, argv,
106	    (isgroups || iswhoami) ? "" : "APGMagnpru")) != -1)
107		switch(ch) {
108#ifdef USE_BSM_AUDIT
109		case 'A':
110			Aflag = 1;
111			break;
112#endif
113		case 'G':
114			Gflag = 1;
115			break;
116		case 'M':
117			Mflag = 1;
118			break;
119		case 'P':
120			Pflag = 1;
121			break;
122		case 'a':
123			break;
124		case 'g':
125			gflag = 1;
126			break;
127		case 'n':
128			nflag = 1;
129			break;
130		case 'p':
131			pflag = 1;
132			break;
133		case 'r':
134			rflag = 1;
135			break;
136		case 'u':
137			uflag = 1;
138			break;
139		case '?':
140		default:
141			usage();
142		}
143	argc -= optind;
144	argv += optind;
145
146	if (iswhoami && argc > 0)
147		usage();
148
149	switch(Aflag + Gflag + Mflag + Pflag + gflag + pflag + uflag) {
150	case 1:
151		break;
152	case 0:
153		if (!nflag && !rflag)
154			break;
155		/* FALLTHROUGH */
156	default:
157		usage();
158	}
159
160	pw = *argv ? who(*argv) : NULL;
161
162	if (Mflag && pw != NULL)
163		usage();
164
165#ifdef USE_BSM_AUDIT
166	if (Aflag) {
167		auditid();
168		exit(0);
169	}
170#endif
171
172	if (gflag) {
173		id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
174		if (nflag && (gr = getgrgid(id)))
175			(void)printf("%s\n", gr->gr_name);
176		else
177			(void)printf("%u\n", id);
178		exit(0);
179	}
180
181	if (uflag) {
182		id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
183		if (nflag && (pw = getpwuid(id)))
184			(void)printf("%s\n", pw->pw_name);
185		else
186			(void)printf("%u\n", id);
187		exit(0);
188	}
189
190	if (Gflag) {
191		group(pw, nflag);
192		exit(0);
193	}
194
195	if (Mflag) {
196		maclabel();
197		exit(0);
198	}
199
200	if (Pflag) {
201		pline(pw);
202		exit(0);
203	}
204
205	if (pflag) {
206		pretty(pw);
207		exit(0);
208	}
209
210	if (pw) {
211		id_print(pw, 1, 0, 0);
212	}
213	else {
214		id = getuid();
215		pw = getpwuid(id);
216		id_print(pw, 0, 1, 1);
217	}
218	exit(0);
219}
220
221void
222pretty(struct passwd *pw)
223{
224	struct group *gr;
225	u_int eid, rid;
226	char *login;
227
228	if (pw) {
229		(void)printf("uid\t%s\n", pw->pw_name);
230		(void)printf("groups\t");
231		group(pw, 1);
232	} else {
233		if ((login = getlogin()) == NULL)
234			err(1, "getlogin");
235
236		pw = getpwuid(rid = getuid());
237		if (pw == NULL || strcmp(login, pw->pw_name))
238			(void)printf("login\t%s\n", login);
239		if (pw)
240			(void)printf("uid\t%s\n", pw->pw_name);
241		else
242			(void)printf("uid\t%u\n", rid);
243
244		if ((eid = geteuid()) != rid) {
245			if ((pw = getpwuid(eid)))
246				(void)printf("euid\t%s\n", pw->pw_name);
247			else
248				(void)printf("euid\t%u\n", eid);
249		}
250		if ((rid = getgid()) != (eid = getegid())) {
251			if ((gr = getgrgid(rid)))
252				(void)printf("rgid\t%s\n", gr->gr_name);
253			else
254				(void)printf("rgid\t%u\n", rid);
255		}
256		(void)printf("groups\t");
257		group(NULL, 1);
258	}
259}
260
261void
262id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
263{
264	struct group *gr;
265	gid_t gid, egid, lastgid;
266	uid_t uid, euid;
267	int cnt, ngroups;
268#ifdef __APPLE__
269	gid_t *groups = NULL;
270#else
271	gid_t groups[NGROUPS + 1];
272#endif
273	const char *fmt;
274
275#ifdef __APPLE__
276	if (pw == NULL) {
277		pw = getpwuid(getuid());
278	}
279
280	use_ggl = 1;
281#endif
282
283	if (pw != NULL) {
284		uid = pw->pw_uid;
285		gid = pw->pw_gid;
286	}
287	else {
288		uid = getuid();
289		gid = getgid();
290	}
291
292	if (use_ggl && pw != NULL) {
293#ifdef __APPLE__
294		// 5235093
295		ngroups = getgrouplist_2(pw->pw_name, gid, &groups);
296#else
297		ngroups = NGROUPS + 1;
298		getgrouplist(pw->pw_name, gid, groups, &ngroups);
299#endif
300	}
301	else {
302#ifdef __APPLE__
303		groups = malloc((NGROUPS + 1) * sizeof(gid_t));
304#endif
305		ngroups = getgroups(NGROUPS + 1, groups);
306	}
307
308#ifdef __APPLE__
309	if (ngroups < 0)
310		warn("failed to retrieve group list");
311#endif
312
313	if (pw != NULL)
314		printf("uid=%u(%s)", uid, pw->pw_name);
315	else
316		printf("uid=%u", getuid());
317	printf(" gid=%u", gid);
318	if ((gr = getgrgid(gid)))
319		(void)printf("(%s)", gr->gr_name);
320	if (p_euid && (euid = geteuid()) != uid) {
321		(void)printf(" euid=%u", euid);
322		if ((pw = getpwuid(euid)))
323			(void)printf("(%s)", pw->pw_name);
324	}
325	if (p_egid && (egid = getegid()) != gid) {
326		(void)printf(" egid=%u", egid);
327		if ((gr = getgrgid(egid)))
328			(void)printf("(%s)", gr->gr_name);
329	}
330	fmt = " groups=%u";
331	for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) {
332		if (lastgid == (gid = groups[cnt]))
333			continue;
334		printf(fmt, gid);
335		fmt = ",%u";
336		if ((gr = getgrgid(gid)))
337			printf("(%s)", gr->gr_name);
338		lastgid = gid;
339	}
340	printf("\n");
341#ifdef __APPLE__
342	free(groups);
343#endif
344}
345
346#ifdef USE_BSM_AUDIT
347void
348auditid(void)
349{
350	auditinfo_addr_t auditinfo;
351
352	if (getaudit_addr(&auditinfo, sizeof(auditinfo)) < 0)
353		err(1, "getaudit");
354	printf("auid=%d\n", auditinfo.ai_auid);
355	printf("mask.success=0x%08x\n", auditinfo.ai_mask.am_success);
356	printf("mask.failure=0x%08x\n", auditinfo.ai_mask.am_failure);
357	printf("termid.port=0x%08x\n", auditinfo.ai_termid.at_port);
358	printf("asid=%d\n", auditinfo.ai_asid);
359}
360#endif
361
362void
363group(struct passwd *pw, int nflag)
364{
365	struct group *gr;
366	int cnt, id, lastid, ngroups;
367#ifdef __APPLE__
368	gid_t *groups = NULL;
369#else
370	gid_t groups[NGROUPS + 1];
371#endif
372	const char *fmt;
373
374#ifdef __APPLE__
375	if (pw == NULL) {
376		pw = getpwuid(getuid());
377	}
378#endif
379
380	if (pw) {
381#ifdef __APPLE__
382		// 5235093
383		ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, &groups);
384#else
385		ngroups = NGROUPS + 1;
386		(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
387#endif
388	} else {
389#ifdef __APPLE__
390		groups = malloc(NGROUPS + 1);
391#endif
392		groups[0] = getgid();
393		ngroups = getgroups(NGROUPS, groups + 1) + 1;
394	}
395	fmt = nflag ? "%s" : "%u";
396	for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
397		if (lastid == (id = groups[cnt]))
398			continue;
399		if (nflag) {
400			if ((gr = getgrgid(id)))
401				(void)printf(fmt, gr->gr_name);
402			else
403				(void)printf(*fmt == ' ' ? " %u" : "%u",
404				    id);
405			fmt = " %s";
406		} else {
407			(void)printf(fmt, id);
408			fmt = " %u";
409		}
410		lastid = id;
411	}
412	(void)printf("\n");
413#ifdef __APPLE__
414	free(groups);
415#endif
416}
417
418void
419maclabel(void)
420{
421#ifdef __APPLE__
422	errx(1, "-M unsupported");
423#else /* !__APPLE__ */
424	char *string;
425	mac_t label;
426	int error;
427
428	error = mac_prepare_process_label(&label);
429	if (error == -1)
430		errx(1, "mac_prepare_type: %s", strerror(errno));
431
432	error = mac_get_proc(label);
433	if (error == -1)
434		errx(1, "mac_get_proc: %s", strerror(errno));
435
436	error = mac_to_text(label, &string);
437	if (error == -1)
438		errx(1, "mac_to_text: %s", strerror(errno));
439
440	(void)printf("%s\n", string);
441	mac_free(label);
442	free(string);
443#endif /* __APPLE__ */
444}
445
446struct passwd *
447who(char *u)
448{
449	struct passwd *pw;
450	long id;
451	char *ep;
452
453	/*
454	 * Translate user argument into a pw pointer.  First, try to
455	 * get it as specified.  If that fails, try it as a number.
456	 */
457	if ((pw = getpwnam(u)))
458		return(pw);
459	id = strtol(u, &ep, 10);
460	if (*u && !*ep && (pw = getpwuid(id)))
461		return(pw);
462	errx(1, "%s: no such user", u);
463	/* NOTREACHED */
464}
465
466void
467pline(struct passwd *pw)
468{
469
470	if (!pw) {
471		if ((pw = getpwuid(getuid())) == NULL)
472			err(1, "getpwuid");
473	}
474
475	(void)printf("%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", pw->pw_name,
476			pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
477			(long)pw->pw_change, (long)pw->pw_expire, pw->pw_gecos,
478			pw->pw_dir, pw->pw_shell);
479}
480
481
482void
483usage(void)
484{
485
486	if (isgroups)
487		(void)fprintf(stderr, "usage: groups [user]\n");
488	else if (iswhoami)
489		(void)fprintf(stderr, "usage: whoami\n");
490	else
491		(void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n",
492		    "usage: id [user]",
493#ifdef USE_BSM_AUDIT
494		    "       id -A\n",
495#else
496		    "",
497#endif
498		    "       id -G [-n] [user]",
499		    "       id -M",
500		    "       id -P [user]",
501		    "       id -g [-nr] [user]",
502		    "       id -p [user]",
503		    "       id -u [-nr] [user]");
504	exit(1);
505}
506