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