xref: /openbsd-src/usr.bin/id/id.c (revision 2119819d27c39b88d37ed54bf0fe45068921d06d)
1 /*	$OpenBSD: id.c,v 1.31 2024/11/04 21:59:15 jca 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 		if (argc != 0)
132 			usage();
133 		printf("%d\n", getrtable());
134 		exit(0);
135 	}
136 
137 	pw = *argv ? who(*argv) : NULL;
138 
139 	if (cflag) {
140 		if (pw == NULL)
141 			pw = getpwuid(getuid());
142 		if (pw != NULL && pw->pw_class != NULL && *pw->pw_class != '\0')
143 			(void)printf("%s\n", pw->pw_class);
144 		else
145 			(void)printf("%s\n", LOGIN_DEFCLASS);
146 		exit(0);
147 	}
148 
149 	if (gflag) {
150 		gid = pw ? pw->pw_gid : rflag ? getgid() : getegid();
151 		if (nflag && (gr = getgrgid(gid)))
152 			(void)printf("%s\n", gr->gr_name);
153 		else
154 			(void)printf("%u\n", gid);
155 		exit(0);
156 	}
157 
158 	if (uflag) {
159 		uid = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
160 		if (nflag && (pw = getpwuid(uid)))
161 			(void)printf("%s\n", pw->pw_name);
162 		else
163 			(void)printf("%u\n", uid);
164 		exit(0);
165 	}
166 
167 	if (Gflag) {
168 		group(pw, nflag);
169 		exit(0);
170 	}
171 
172 	if (pflag) {
173 		pretty(pw);
174 		exit(0);
175 	}
176 
177 	if (pw)
178 		user(pw);
179 	else
180 		current();
181 	exit(0);
182 }
183 
184 void
185 pretty(struct passwd *pw)
186 {
187 	struct group *gr;
188 	uid_t eid, rid;
189 	char *login;
190 
191 	if (pw) {
192 		(void)printf("uid\t%s\n", pw->pw_name);
193 		(void)printf("groups\t");
194 		group(pw, 1);
195 	} else {
196 		if ((login = getlogin()) == NULL)
197 			err(1, "getlogin");
198 
199 		pw = getpwuid(rid = getuid());
200 		if (pw == NULL || strcmp(login, pw->pw_name))
201 			(void)printf("login\t%s\n", login);
202 		if (pw)
203 			(void)printf("uid\t%s\n", pw->pw_name);
204 		else
205 			(void)printf("uid\t%u\n", rid);
206 
207 		if ((eid = geteuid()) != rid) {
208 			if ((pw = getpwuid(eid)))
209 				(void)printf("euid\t%s\n", pw->pw_name);
210 			else
211 				(void)printf("euid\t%u\n", eid);
212 		}
213 		if ((rid = getgid()) != (eid = getegid())) {
214 			if ((gr = getgrgid(rid)))
215 				(void)printf("rgid\t%s\n", gr->gr_name);
216 			else
217 				(void)printf("rgid\t%u\n", rid);
218 		}
219 		(void)printf("groups\t");
220 		group(NULL, 1);
221 	}
222 	if (pw != NULL && pw->pw_class != NULL && *pw->pw_class != '\0')
223 		(void)printf("class\t%s\n", pw->pw_class);
224 }
225 
226 void
227 current(void)
228 {
229 	struct group *gr;
230 	struct passwd *pw;
231 	int cnt, ngroups;
232 	uid_t uid, euid;
233 	gid_t groups[NGROUPS_MAX], gid, egid, lastgid;
234 	char *prefix;
235 
236 	uid = getuid();
237 	(void)printf("uid=%u", uid);
238 	if ((pw = getpwuid(uid)))
239 		(void)printf("(%s)", pw->pw_name);
240 	if ((euid = geteuid()) != uid) {
241 		(void)printf(" euid=%u", euid);
242 		if ((pw = getpwuid(euid)))
243 			(void)printf("(%s)", pw->pw_name);
244 	}
245 	gid = getgid();
246 	(void)printf(" gid=%u", gid);
247 	if ((gr = getgrgid(gid)))
248 		(void)printf("(%s)", gr->gr_name);
249 	if ((egid = getegid()) != gid) {
250 		(void)printf(" egid=%u", egid);
251 		if ((gr = getgrgid(egid)))
252 			(void)printf("(%s)", gr->gr_name);
253 	}
254 	if ((ngroups = getgroups(NGROUPS_MAX, groups))) {
255 		for (prefix = " groups=", lastgid = (gid_t)-1, cnt = 0;
256 		    cnt < ngroups; prefix = ", ", lastgid = gid) {
257 			gid = groups[cnt++];
258 			if (lastgid == gid)
259 				continue;
260 			(void)printf("%s%u", prefix, gid);
261 			if ((gr = getgrgid(gid)))
262 				(void)printf("(%s)", gr->gr_name);
263 		}
264 	}
265 	(void)printf("\n");
266 }
267 
268 void
269 user(struct passwd *pw)
270 {
271 	gid_t gid, groups[NGROUPS_MAX + 1];
272 	int cnt, maxgroups, ngroups;
273 	uid_t uid;
274 	struct group *gr;
275 	char *prefix;
276 
277 	uid = pw->pw_uid;
278 	(void)printf("uid=%u(%s)", uid, pw->pw_name);
279 	(void)printf(" gid=%u", pw->pw_gid);
280 	if ((gr = getgrgid(pw->pw_gid)))
281 		(void)printf("(%s)", gr->gr_name);
282 	maxgroups = ngroups = NGROUPS_MAX + 1;
283 	if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) {
284 		/* Silently truncate group list */
285 		ngroups = maxgroups;
286 	}
287 	prefix = " groups=";
288 	for (cnt = 0; cnt < ngroups;) {
289 		gid = groups[cnt];
290 		(void)printf("%s%u", prefix, gid);
291 		prefix = ", ";
292 		if ((gr = getgrgid(gid)))
293 			(void)printf("(%s)", gr->gr_name);
294 		/* Skip same gid entries. */
295 		while (++cnt < ngroups && gid == groups[cnt])
296 			;
297 	}
298 	(void)printf("\n");
299 }
300 
301 void
302 group(struct passwd *pw, int nflag)
303 {
304 	int cnt, maxgroups, ngroups;
305 	gid_t gid, groups[NGROUPS_MAX + 1];
306 	struct group *gr;
307 	char *prefix;
308 
309 	if (pw) {
310 		int ret;
311 
312 		maxgroups = ngroups = NGROUPS_MAX + 1;
313 		ret = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
314 		if (ret == -1) {
315 			/* Silently truncate group list */
316 			ngroups = maxgroups;
317 		}
318 	} else {
319 		groups[0] = getgid();
320 		ngroups = getgroups(NGROUPS_MAX, groups + 1) + 1;
321 	}
322 	prefix = "";
323 	for (cnt = 0; cnt < ngroups;) {
324 		gid = groups[cnt];
325 		if (nflag) {
326 			if ((gr = getgrgid(gid)))
327 				(void)printf("%s%s", prefix, gr->gr_name);
328 			else
329 				(void)printf("%s%u", prefix, gid);
330 		} else {
331 			(void)printf("%s%u", prefix, gid);
332 		}
333 		prefix = " ";
334 		/* Skip same gid entries. */
335 		while (++cnt < ngroups && gid == groups[cnt])
336 			;
337 	}
338 	(void)printf("\n");
339 }
340 
341 struct passwd *
342 who(char *u)
343 {
344 	struct passwd *pw;
345 	uid_t uid;
346 	const char *errstr;
347 
348 	/*
349 	 * Translate user argument into a pw pointer.  First, try to
350 	 * get it as specified.  If that fails, try it as a number.
351 	 */
352 	if ((pw = getpwnam(u)))
353 		return(pw);
354 	uid = strtonum(u, 0, UID_MAX, &errstr);
355 	if (!errstr && (pw = getpwuid(uid)))
356 		return(pw);
357 	errx(1, "%s: No such user", u);
358 	/* NOTREACHED */
359 }
360 
361 void
362 usage(void)
363 {
364 	if (strcmp(getprogname(), "groups") == 0) {
365 		(void)fprintf(stderr, "usage: groups [user]\n");
366 	} else if (strcmp(getprogname(), "whoami") == 0) {
367 		(void)fprintf(stderr, "usage: whoami\n");
368 	} else {
369 		(void)fprintf(stderr, "usage: id [user]\n");
370 		(void)fprintf(stderr, "       id -c [user]\n");
371 		(void)fprintf(stderr, "       id -G [-n] [user]\n");
372 		(void)fprintf(stderr, "       id -g [-nr] [user]\n");
373 		(void)fprintf(stderr, "       id -p [user]\n");
374 		(void)fprintf(stderr, "       id -R\n");
375 		(void)fprintf(stderr, "       id -u [-nr] [user]\n");
376 	}
377 	exit(1);
378 }
379