xref: /openbsd-src/usr.bin/id/id.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: id.c,v 1.26 2015/10/09 01:37:07 deraadt 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 <err.h>
33 #include <errno.h>
34 #include <grp.h>
35 #include <pwd.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <limits.h>
41 #include <login_cap.h>
42 
43 void	current(void);
44 void	pretty(struct passwd *);
45 void	group(struct passwd *, int);
46 void	usage(void);
47 void	user(struct passwd *);
48 struct passwd *
49 	who(char *);
50 
51 int
52 main(int argc, char *argv[])
53 {
54 	struct group *gr;
55 	struct passwd *pw;
56 	int ch, cflag, Gflag, gflag, nflag, pflag, rflag, uflag;
57 	uid_t uid;
58 	gid_t gid;
59 	const char *opts;
60 
61 	if (pledge("stdio getpw", NULL) == -1)
62 		err(1, "pledge");
63 
64 	cflag = Gflag = gflag = nflag = pflag = rflag = uflag = 0;
65 
66 	if (strcmp(getprogname(), "groups") == 0) {
67 		Gflag = 1;
68 		nflag = 1;
69 		opts = "";
70 		if (argc > 2)
71 			usage();
72 	} else if (strcmp(getprogname(), "whoami") == 0) {
73 		uflag = 1;
74 		nflag = 1;
75 		opts = "";
76 		if (argc > 1)
77 			usage();
78 	} else
79 		opts = "cGgnpru";
80 
81 	while ((ch = getopt(argc, argv, opts)) != -1)
82 		switch(ch) {
83 		case 'c':
84 			cflag = 1;
85 			break;
86 		case 'G':
87 			Gflag = 1;
88 			break;
89 		case 'g':
90 			gflag = 1;
91 			break;
92 		case 'n':
93 			nflag = 1;
94 			break;
95 		case 'p':
96 			pflag = 1;
97 			break;
98 		case 'r':
99 			rflag = 1;
100 			break;
101 		case 'u':
102 			uflag = 1;
103 			break;
104 		case '?':
105 		default:
106 			usage();
107 		}
108 	argc -= optind;
109 	argv += optind;
110 
111 	switch (cflag + Gflag + gflag + pflag + uflag) {
112 	case 1:
113 		break;
114 	case 0:
115 		if (!nflag && !rflag)
116 			break;
117 		/* FALLTHROUGH */
118 	default:
119 		usage();
120 	}
121 
122 	if (strcmp(opts, "") != 0 && argc > 1)
123 		usage();
124 
125 	pw = *argv ? who(*argv) : NULL;
126 
127 	if (cflag) {
128 		if (pw == NULL)
129 			pw = getpwuid(getuid());
130 		if (pw != NULL && pw->pw_class != NULL && *pw->pw_class != '\0')
131 			(void)printf("%s\n", pw->pw_class);
132 		else
133 			(void)printf("%s\n", LOGIN_DEFCLASS);
134 		exit(0);
135 	}
136 
137 	if (gflag) {
138 		gid = pw ? pw->pw_gid : rflag ? getgid() : getegid();
139 		if (nflag && (gr = getgrgid(gid)))
140 			(void)printf("%s\n", gr->gr_name);
141 		else
142 			(void)printf("%u\n", gid);
143 		exit(0);
144 	}
145 
146 	if (uflag) {
147 		uid = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
148 		if (nflag && (pw = getpwuid(uid)))
149 			(void)printf("%s\n", pw->pw_name);
150 		else
151 			(void)printf("%u\n", uid);
152 		exit(0);
153 	}
154 
155 	if (Gflag) {
156 		group(pw, nflag);
157 		exit(0);
158 	}
159 
160 	if (pflag) {
161 		pretty(pw);
162 		exit(0);
163 	}
164 
165 	if (pw)
166 		user(pw);
167 	else
168 		current();
169 	exit(0);
170 }
171 
172 void
173 pretty(struct passwd *pw)
174 {
175 	struct group *gr;
176 	uid_t eid, rid;
177 	char *login;
178 
179 	if (pw) {
180 		(void)printf("uid\t%s\n", pw->pw_name);
181 		(void)printf("groups\t");
182 		group(pw, 1);
183 	} else {
184 		if ((login = getlogin()) == NULL)
185 			err(1, "getlogin");
186 
187 		pw = getpwuid(rid = getuid());
188 		if (pw == NULL || strcmp(login, pw->pw_name))
189 			(void)printf("login\t%s\n", login);
190 		if (pw)
191 			(void)printf("uid\t%s\n", pw->pw_name);
192 		else
193 			(void)printf("uid\t%u\n", rid);
194 
195 		if ((eid = geteuid()) != rid) {
196 			if ((pw = getpwuid(eid)))
197 				(void)printf("euid\t%s\n", pw->pw_name);
198 			else
199 				(void)printf("euid\t%u\n", eid);
200 		}
201 		if ((rid = getgid()) != (eid = getegid())) {
202 			if ((gr = getgrgid(rid)))
203 				(void)printf("rgid\t%s\n", gr->gr_name);
204 			else
205 				(void)printf("rgid\t%u\n", rid);
206 		}
207 		(void)printf("groups\t");
208 		group(NULL, 1);
209 	}
210 	if (pw != NULL && pw->pw_class != NULL && *pw->pw_class != '\0')
211 		(void)printf("class\t%s\n", pw->pw_class);
212 }
213 
214 void
215 current(void)
216 {
217 	struct group *gr;
218 	struct passwd *pw;
219 	int cnt, ngroups;
220 	uid_t uid, euid;
221 	gid_t groups[NGROUPS_MAX], gid, egid, lastgid;
222 	char *prefix;
223 
224 	uid = getuid();
225 	(void)printf("uid=%u", uid);
226 	if ((pw = getpwuid(uid)))
227 		(void)printf("(%s)", pw->pw_name);
228 	if ((euid = geteuid()) != uid) {
229 		(void)printf(" euid=%u", euid);
230 		if ((pw = getpwuid(euid)))
231 			(void)printf("(%s)", pw->pw_name);
232 	}
233 	gid = getgid();
234 	(void)printf(" gid=%u", gid);
235 	if ((gr = getgrgid(gid)))
236 		(void)printf("(%s)", gr->gr_name);
237 	if ((egid = getegid()) != gid) {
238 		(void)printf(" egid=%u", egid);
239 		if ((gr = getgrgid(egid)))
240 			(void)printf("(%s)", gr->gr_name);
241 	}
242 	if ((ngroups = getgroups(NGROUPS_MAX, groups))) {
243 		for (prefix = " groups=", lastgid = (gid_t)-1, cnt = 0;
244 		    cnt < ngroups; prefix = ", ", lastgid = gid) {
245 			gid = groups[cnt++];
246 			if (lastgid == gid)
247 				continue;
248 			(void)printf("%s%u", prefix, gid);
249 			if ((gr = getgrgid(gid)))
250 				(void)printf("(%s)", gr->gr_name);
251 		}
252 	}
253 	(void)printf("\n");
254 }
255 
256 void
257 user(struct passwd *pw)
258 {
259 	gid_t gid, groups[NGROUPS_MAX + 1];
260 	int cnt, ngroups;
261 	uid_t uid;
262 	struct group *gr;
263 	char *prefix;
264 
265 	uid = pw->pw_uid;
266 	(void)printf("uid=%u(%s)", uid, pw->pw_name);
267 	(void)printf(" gid=%u", pw->pw_gid);
268 	if ((gr = getgrgid(pw->pw_gid)))
269 		(void)printf("(%s)", gr->gr_name);
270 	ngroups = NGROUPS_MAX + 1;
271 	(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
272 	prefix = " groups=";
273 	for (cnt = 0; cnt < ngroups;) {
274 		gid = groups[cnt];
275 		(void)printf("%s%u", prefix, gid);
276 		prefix = ", ";
277 		if ((gr = getgrgid(gid)))
278 			(void)printf("(%s)", gr->gr_name);
279 		/* Skip same gid entries. */
280 		while (++cnt < ngroups && gid == groups[cnt])
281 			;
282 	}
283 	(void)printf("\n");
284 }
285 
286 void
287 group(struct passwd *pw, int nflag)
288 {
289 	int cnt, ngroups;
290 	gid_t gid, groups[NGROUPS_MAX + 1];
291 	struct group *gr;
292 	char *prefix;
293 
294 	if (pw) {
295 		ngroups = NGROUPS_MAX + 1;
296 		(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
297 	} else {
298 		groups[0] = getgid();
299 		ngroups = getgroups(NGROUPS_MAX, groups + 1) + 1;
300 	}
301 	prefix = "";
302 	for (cnt = 0; cnt < ngroups;) {
303 		gid = groups[cnt];
304 		if (nflag) {
305 			if ((gr = getgrgid(gid)))
306 				(void)printf("%s%s", prefix, gr->gr_name);
307 			else
308 				(void)printf("%s%u", prefix, gid);
309 		} else {
310 			(void)printf("%s%u", prefix, gid);
311 		}
312 		prefix = " ";
313 		/* Skip same gid entries. */
314 		while (++cnt < ngroups && gid == groups[cnt])
315 			;
316 	}
317 	(void)printf("\n");
318 }
319 
320 struct passwd *
321 who(char *u)
322 {
323 	struct passwd *pw;
324 	uid_t uid;
325 	const char *errstr;
326 
327 	/*
328 	 * Translate user argument into a pw pointer.  First, try to
329 	 * get it as specified.  If that fails, try it as a number.
330 	 */
331 	if ((pw = getpwnam(u)))
332 		return(pw);
333 	uid = strtonum(u, 0, UID_MAX, &errstr);
334 	if (!errstr && (pw = getpwuid(uid)))
335 		return(pw);
336 	errx(1, "%s: No such user", u);
337 	/* NOTREACHED */
338 }
339 
340 void
341 usage(void)
342 {
343 	if (strcmp(getprogname(), "groups") == 0) {
344 		(void)fprintf(stderr, "usage: groups [user]\n");
345 	} else if (strcmp(getprogname(), "whoami") == 0) {
346 		(void)fprintf(stderr, "usage: whoami\n");
347 	} else {
348 		(void)fprintf(stderr, "usage: id [user]\n");
349 		(void)fprintf(stderr, "       id -c [user]\n");
350 		(void)fprintf(stderr, "       id -G [-n] [user]\n");
351 		(void)fprintf(stderr, "       id -g [-nr] [user]\n");
352 		(void)fprintf(stderr, "       id -p [user]\n");
353 		(void)fprintf(stderr, "       id -u [-nr] [user]\n");
354 	}
355 	exit(1);
356 }
357