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