xref: /openbsd-src/usr.bin/getent/getent.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: getent.c,v 1.14 2016/02/01 19:57:28 jca Exp $	*/
2 /*	$NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $	*/
3 
4 /*-
5  * Copyright (c) 2004 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Luke Mewburn.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <grp.h>
40 #include <limits.h>
41 #include <netdb.h>
42 #include <pwd.h>
43 #include <stdio.h>
44 #include <stdarg.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 
49 #include <net/if.h>
50 #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
51 #include <netinet/if_ether.h>
52 
53 #include <arpa/inet.h>
54 #include <arpa/nameser.h>
55 
56 #include <rpc/rpc.h>
57 
58 static int	usage(void);
59 static int	ethers(int, char *[]);
60 static int	group(int, char *[]);
61 static int	hosts(int, char *[]);
62 static int	passwd(int, char *[]);
63 static int	protocols(int, char *[]);
64 static int	rpc(int, char *[]);
65 static int	services(int, char *[]);
66 static int	shells(int, char *[]);
67 extern char *__progname;
68 
69 enum {
70 	RV_OK		= 0,
71 	RV_USAGE	= 1,
72 	RV_NOTFOUND	= 2,
73 	RV_NOENUM	= 3
74 };
75 
76 static struct getentdb {
77 	const char	*name;
78 	int		(*fn)(int, char *[]);
79 	const char	*pledge;
80 } databases[] = {
81 	{	"ethers",	ethers,		"stdio rpath"	},
82 	{	"group",	group,		"stdio getpw"	},
83 	{	"hosts",	hosts,		"stdio dns"	},
84 	{	"passwd",	passwd,		"stdio getpw"	},
85 	{	"protocols",	protocols,	"stdio rpath"	},
86 	{	"rpc",		rpc,		"stdio rpath"	},
87 	{	"services",	services,	"stdio rpath"	},
88 	{	"shells",	shells,		"stdio rpath"	},
89 
90 	{	NULL,		NULL,				},
91 };
92 
93 int
94 main(int argc, char *argv[])
95 {
96 	struct getentdb	*curdb;
97 
98 	if (pledge("stdio dns rpath getpw", NULL) == -1)
99 		err(1, "pledge");
100 
101 	if (argc < 2)
102 		usage();
103 	for (curdb = databases; curdb->name != NULL; curdb++) {
104 		if (strcmp(curdb->name, argv[1]) == 0) {
105 			if (pledge(curdb->pledge, NULL) == -1)
106 				err(1, "pledge");
107 
108 			exit(curdb->fn(argc, argv));
109 			break;
110 		}
111 	}
112 	fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]);
113 	return RV_USAGE;
114 }
115 
116 static int
117 usage(void)
118 {
119 	fprintf(stderr, "usage: %s database [key ...]\n", __progname);
120 	exit(RV_USAGE);
121 	/* NOTREACHED */
122 }
123 
124 /*
125  * printfmtstrings --
126  *	vprintf(format, ...),
127  *	then the aliases (beginning with prefix, separated by sep),
128  *	then a newline
129  */
130 static void
131 printfmtstrings(char *strings[], const char *prefix, const char *sep,
132 	const char *fmt, ...)
133 {
134 	va_list		ap;
135 	const char	*curpref;
136 	int		i;
137 
138 	va_start(ap, fmt);
139 	vprintf(fmt, ap);
140 	va_end(ap);
141 
142 	curpref = prefix;
143 	for (i = 0; strings[i] != NULL; i++) {
144 		printf("%s%s", curpref, strings[i]);
145 		curpref = sep;
146 	}
147 	printf("\n");
148 }
149 
150 #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
151 
152 static int
153 ethers(int argc, char *argv[])
154 {
155 	char		hostname[HOST_NAME_MAX+1], *hp;
156 	int		i, rv = RV_OK;
157 	struct ether_addr ea, *eap;
158 
159 	if (argc == 2) {
160 		fprintf(stderr, "%s: Enumeration not supported on ethers\n",
161 		    __progname);
162 		rv = RV_NOENUM;
163 	} else {
164 		for (i = 2; i < argc; i++) {
165 			if ((eap = ether_aton(argv[i])) == NULL) {
166 				eap = &ea;
167 				hp = argv[i];
168 				if (ether_hostton(hp, eap) != 0) {
169 					rv = RV_NOTFOUND;
170 					break;
171 				}
172 			} else {
173 				hp = hostname;
174 				if (ether_ntohost(hp, eap) != 0) {
175 					rv = RV_NOTFOUND;
176 					break;
177 				}
178 			}
179 			ETHERSPRINT;
180 		}
181 	}
182 	return rv;
183 }
184 
185 #define GROUPPRINT	\
186 	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
187 	    gr->gr_name, gr->gr_passwd, gr->gr_gid)
188 
189 static int
190 group(int argc, char *argv[])
191 {
192 	int		i, rv = RV_OK;
193 	struct group	*gr;
194 
195 	setgroupent(1);
196 	if (argc == 2) {
197 		while ((gr = getgrent()) != NULL)
198 			GROUPPRINT;
199 	} else {
200 		for (i = 2; i < argc; i++) {
201 			const char	*err;
202 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
203 
204 			if (!err)
205 				gr = getgrgid((gid_t)id);
206 			else
207 				gr = getgrnam(argv[i]);
208 			if (gr != NULL)
209 				GROUPPRINT;
210 			else {
211 				rv = RV_NOTFOUND;
212 				break;
213 			}
214 		}
215 	}
216 	endgrent();
217 	return rv;
218 }
219 
220 static void
221 hostsprint(const struct hostent *he)
222 {
223 	char	buf[INET6_ADDRSTRLEN];
224 
225 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
226 		strlcpy(buf, "# unknown", sizeof(buf));
227 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
228 }
229 static int
230 hostsaddrinfo(char* name)
231 {
232 	struct addrinfo	 hints, *res, *res0;
233 	void		*src;
234 	int		 rv;
235 	char		 buf[INET6_ADDRSTRLEN];
236 
237 	rv = RV_NOTFOUND;
238 	memset(buf, 0, sizeof(buf));
239 	memset(&hints, 0, sizeof(hints));
240 	hints.ai_family = PF_UNSPEC;
241 	hints.ai_socktype = SOCK_DGRAM;
242 
243 	if (getaddrinfo(name, NULL, &hints, &res0) == 0) {
244 		for (res = res0; res; res = res->ai_next) {
245 			switch (res->ai_family) {
246 			case AF_INET:
247 				src = &((struct sockaddr_in*)
248 				    res->ai_addr)->sin_addr;
249 				break;
250 			case AF_INET6:
251 				src = &((struct sockaddr_in6*)
252 				    res->ai_addr)->sin6_addr;
253 				break;
254 			default: /* not reached */
255 				src = NULL;
256 			}
257 			if (src==NULL || inet_ntop(res->ai_family, src, buf,
258 			    sizeof(buf)) == NULL)
259 				strlcpy(buf, "# unknown", sizeof(buf));
260 			else
261 				rv = RV_OK;
262 			printf("%-39s %s\n", buf, name);
263 		}
264 		freeaddrinfo(res0);
265 	}
266 
267 	return (rv);
268 }
269 
270 static int
271 hosts(int argc, char *argv[])
272 {
273 	char		addr[IN6ADDRSZ];
274 	int		i, rv = RV_OK;
275 	struct hostent	*he;
276 
277 	if (argc == 2) {
278 		fprintf(stderr, "%s: Enumeration not supported on hosts\n",
279 		    __progname);
280 		rv = RV_NOENUM;
281 	} else {
282 		for (i = 2; i < argc; i++) {
283 			he = NULL;
284 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
285 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
286 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
287 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
288 			if (he != NULL)
289 				hostsprint(he);
290 			else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
291 				break;
292 		}
293 	}
294 	return rv;
295 }
296 
297 #define PASSWDPRINT	\
298 	printf("%s:%s:%u:%u:%s:%s:%s\n", \
299 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
300 	    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
301 
302 static int
303 passwd(int argc, char *argv[])
304 {
305 	int		i, rv = RV_OK;
306 	struct passwd	*pw;
307 
308 	setpassent(1);
309 	if (argc == 2) {
310 		while ((pw = getpwent()) != NULL)
311 			PASSWDPRINT;
312 	} else {
313 		for (i = 2; i < argc; i++) {
314 			const char	*err;
315 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
316 
317 			if (!err)
318 				pw = getpwuid((uid_t)id);
319 			else
320 				pw = getpwnam(argv[i]);
321 			if (pw != NULL)
322 				PASSWDPRINT;
323 			else {
324 				rv = RV_NOTFOUND;
325 				break;
326 			}
327 		}
328 	}
329 	endpwent();
330 	return rv;
331 }
332 
333 #define PROTOCOLSPRINT	\
334 	printfmtstrings(pe->p_aliases, "  ", " ", \
335 	    "%-16s  %5d", pe->p_name, pe->p_proto)
336 
337 static int
338 protocols(int argc, char *argv[])
339 {
340 	struct protoent	*pe;
341 	int		i, rv = RV_OK;
342 
343 	setprotoent(1);
344 	if (argc == 2) {
345 		while ((pe = getprotoent()) != NULL)
346 			PROTOCOLSPRINT;
347 	} else {
348 		for (i = 2; i < argc; i++) {
349 			const char	*err;
350 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
351 
352 			if (!err)
353 				pe = getprotobynumber((int)id);
354 			else
355 				pe = getprotobyname(argv[i]);
356 			if (pe != NULL)
357 				PROTOCOLSPRINT;
358 			else {
359 				rv = RV_NOTFOUND;
360 				break;
361 			}
362 		}
363 	}
364 	endprotoent();
365 	return rv;
366 }
367 
368 #define RPCPRINT	\
369 	printfmtstrings(re->r_aliases, "  ", " ", \
370 	    "%-16s  %6d", re->r_name, re->r_number)
371 
372 static int
373 rpc(int argc, char *argv[])
374 {
375 	struct rpcent	*re;
376 	int		i, rv = RV_OK;
377 
378 	setrpcent(1);
379 	if (argc == 2) {
380 		while ((re = getrpcent()) != NULL)
381 			RPCPRINT;
382 	} else {
383 		for (i = 2; i < argc; i++) {
384 			const char	*err;
385 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
386 
387 			if (!err)
388 				re = getrpcbynumber((int)id);
389 			else
390 				re = getrpcbyname(argv[i]);
391 			if (re != NULL)
392 				RPCPRINT;
393 			else {
394 				rv = RV_NOTFOUND;
395 				break;
396 			}
397 		}
398 	}
399 	endrpcent();
400 	return rv;
401 }
402 
403 #define SERVICESPRINT	\
404 	printfmtstrings(se->s_aliases, "  ", " ", \
405 	    "%-16s  %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
406 
407 static int
408 services(int argc, char *argv[])
409 {
410 	struct servent	*se;
411 	int		i, rv = RV_OK;
412 
413 	setservent(1);
414 	if (argc == 2) {
415 		while ((se = getservent()) != NULL)
416 			SERVICESPRINT;
417 	} else {
418 		for (i = 2; i < argc; i++) {
419 			const char	*err;
420 			long long	id;
421 			char *proto = strchr(argv[i], '/');
422 
423 			if (proto != NULL)
424 				*proto++ = '\0';
425 			id = strtonum(argv[i], 0, UINT_MAX, &err);
426 			if (!err)
427 				se = getservbyport(htons((u_short)id), proto);
428 			else
429 				se = getservbyname(argv[i], proto);
430 			if (se != NULL)
431 				SERVICESPRINT;
432 			else {
433 				rv = RV_NOTFOUND;
434 				break;
435 			}
436 		}
437 	}
438 	endservent();
439 	return rv;
440 }
441 
442 #define SHELLSPRINT	printf("%s\n", sh)
443 
444 static int
445 shells(int argc, char *argv[])
446 {
447 	const char	*sh;
448 	int		i, rv = RV_OK;
449 
450 	setusershell();
451 	if (argc == 2) {
452 		while ((sh = getusershell()) != NULL)
453 			SHELLSPRINT;
454 	} else {
455 		for (i = 2; i < argc; i++) {
456 			setusershell();
457 			while ((sh = getusershell()) != NULL) {
458 				if (strcmp(sh, argv[i]) == 0) {
459 					SHELLSPRINT;
460 					break;
461 				}
462 			}
463 			if (sh == NULL) {
464 				rv = RV_NOTFOUND;
465 				break;
466 			}
467 		}
468 	}
469 	endusershell();
470 	return rv;
471 }
472