xref: /openbsd-src/usr.bin/getent/getent.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: getent.c,v 1.6 2013/03/30 14:03:08 florian 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 <errno.h>
38 #include <grp.h>
39 #include <limits.h>
40 #include <netdb.h>
41 #include <pwd.h>
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47 
48 #include <net/if.h>
49 #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
50 #include <netinet/if_ether.h>
51 
52 #include <arpa/inet.h>
53 #include <arpa/nameser.h>
54 
55 #include <rpc/rpc.h>
56 
57 static int	usage(void);
58 static int	ethers(int, char *[]);
59 static int	group(int, char *[]);
60 static int	hosts(int, char *[]);
61 static int	networks(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 } databases[] = {
80 	{	"ethers",	ethers,		},
81 	{	"group",	group,		},
82 	{	"hosts",	hosts,		},
83 	{	"networks",	networks,	},
84 	{	"passwd",	passwd,		},
85 	{	"protocols",	protocols,	},
86 	{	"rpc",		rpc,		},
87 	{	"services",	services,	},
88 	{	"shells",	shells,		},
89 
90 	{	NULL,		NULL,		},
91 };
92 
93 int
94 main(int argc, char *argv[])
95 {
96 	struct getentdb	*curdb;
97 
98 	if (argc < 2)
99 		usage();
100 	for (curdb = databases; curdb->name != NULL; curdb++) {
101 		if (strcmp(curdb->name, argv[1]) == 0) {
102 			exit(curdb->fn(argc, argv));
103 			break;
104 		}
105 	}
106 	fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]);
107 	return RV_USAGE;
108 }
109 
110 static int
111 usage(void)
112 {
113 	fprintf(stderr, "usage: %s database [key ...]\n", __progname);
114 	exit(RV_USAGE);
115 	/* NOTREACHED */
116 }
117 
118 /*
119  * printfmtstrings --
120  *	vprintf(format, ...),
121  *	then the aliases (beginning with prefix, separated by sep),
122  *	then a newline
123  */
124 static void
125 printfmtstrings(char *strings[], const char *prefix, const char *sep,
126 	const char *fmt, ...)
127 {
128 	va_list		ap;
129 	const char	*curpref;
130 	int		i;
131 
132 	va_start(ap, fmt);
133 	vprintf(fmt, ap);
134 	va_end(ap);
135 
136 	curpref = prefix;
137 	for (i = 0; strings[i] != NULL; i++) {
138 		printf("%s%s", curpref, strings[i]);
139 		curpref = sep;
140 	}
141 	printf("\n");
142 }
143 
144 #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
145 
146 static int
147 ethers(int argc, char *argv[])
148 {
149 	char		hostname[MAXHOSTNAMELEN], *hp;
150 	int		i, rv = RV_OK;
151 	struct ether_addr ea, *eap;
152 
153 	if (argc == 2) {
154 		fprintf(stderr, "%s: Enumeration not supported on ethers\n",
155 		    __progname);
156 		rv = RV_NOENUM;
157 	} else {
158 		for (i = 2; i < argc; i++) {
159 			if ((eap = ether_aton(argv[i])) == NULL) {
160 				eap = &ea;
161 				hp = argv[i];
162 				if (ether_hostton(hp, eap) != 0) {
163 					rv = RV_NOTFOUND;
164 					break;
165 				}
166 			} else {
167 				hp = hostname;
168 				if (ether_ntohost(hp, eap) != 0) {
169 					rv = RV_NOTFOUND;
170 					break;
171 				}
172 			}
173 			ETHERSPRINT;
174 		}
175 	}
176 	return rv;
177 }
178 
179 #define GROUPPRINT	\
180 	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
181 	    gr->gr_name, gr->gr_passwd, gr->gr_gid)
182 
183 static int
184 group(int argc, char *argv[])
185 {
186 	int		i, rv = RV_OK;
187 	struct group	*gr;
188 
189 	setgroupent(1);
190 	if (argc == 2) {
191 		while ((gr = getgrent()) != NULL)
192 			GROUPPRINT;
193 	} else {
194 		for (i = 2; i < argc; i++) {
195 			const char	*err;
196 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
197 
198 			if (!err)
199 				gr = getgrgid((gid_t)id);
200 			else
201 				gr = getgrnam(argv[i]);
202 			if (gr != NULL)
203 				GROUPPRINT;
204 			else {
205 				rv = RV_NOTFOUND;
206 				break;
207 			}
208 		}
209 	}
210 	endgrent();
211 	return rv;
212 }
213 
214 static void
215 hostsprint(const struct hostent *he)
216 {
217 	char	buf[INET6_ADDRSTRLEN];
218 
219 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
220 		strlcpy(buf, "# unknown", sizeof(buf));
221 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
222 }
223 static int
224 hostsaddrinfo(char* name)
225 {
226 	struct addrinfo	 hints, *res, *res0;
227 	void		*src;
228 	int		 rv;
229 	char		 buf[INET6_ADDRSTRLEN];
230 
231 	rv = RV_NOTFOUND;
232 	memset(buf, 0, sizeof(buf));
233 	memset(&hints, 0, sizeof(hints));
234 	hints.ai_family = PF_UNSPEC;
235 	hints.ai_socktype = SOCK_DGRAM;
236 
237 	if (getaddrinfo(name, NULL, &hints, &res0) == 0) {
238 		for (res = res0; res; res = res->ai_next) {
239 			switch (res->ai_family) {
240 			case AF_INET:
241 				src = &((struct sockaddr_in*)
242 				    res->ai_addr)->sin_addr;
243 				break;
244 			case AF_INET6:
245 				src = &((struct sockaddr_in6*)
246 				    res->ai_addr)->sin6_addr;
247 				break;
248 			default: /* not reached */
249 				src = NULL;
250 			}
251 			if (src==NULL || inet_ntop(res->ai_family, src, buf,
252 			    sizeof(buf)) == NULL)
253 				strlcpy(buf, "# unknown", sizeof(buf));
254 			else
255 				rv = RV_OK;
256 			printf("%-39s %s\n", buf, name);
257 		}
258 		freeaddrinfo(res0);
259 	}
260 
261 	return (rv);
262 }
263 
264 static int
265 hosts(int argc, char *argv[])
266 {
267 	char		addr[IN6ADDRSZ];
268 	int		i, rv = RV_OK;
269 	struct hostent	*he;
270 
271 	sethostent(1);
272 	if (argc == 2) {
273 		while ((he = gethostent()) != NULL)
274 			hostsprint(he);
275 	} else {
276 		for (i = 2; i < argc; i++) {
277 			he = NULL;
278 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
279 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
280 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
281 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
282 			if (he != NULL)
283 				hostsprint(he);
284 			else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
285 				break;
286 		}
287 	}
288 	endhostent();
289 	return rv;
290 }
291 
292 static void
293 networksprint(const struct netent *ne)
294 {
295 	char		buf[INET6_ADDRSTRLEN];
296 	struct in_addr	ianet;
297 
298 	ianet = inet_makeaddr(ne->n_net, 0);
299 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
300 		strlcpy(buf, "# unknown", sizeof(buf));
301 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
302 }
303 
304 static int
305 networks(int argc, char *argv[])
306 {
307 	int		i, rv = RV_OK;
308 	struct netent	*ne;
309 	in_addr_t	net;
310 
311 	setnetent(1);
312 	if (argc == 2) {
313 		while ((ne = getnetent()) != NULL)
314 			networksprint(ne);
315 	} else {
316 		for (i = 2; i < argc; i++) {
317 			net = inet_network(argv[i]);
318 			if (net != INADDR_NONE)
319 				ne = getnetbyaddr(net, AF_INET);
320 			else
321 				ne = getnetbyname(argv[i]);
322 			if (ne != NULL)
323 				networksprint(ne);
324 			else {
325 				rv = RV_NOTFOUND;
326 				break;
327 			}
328 		}
329 	}
330 	endnetent();
331 	return rv;
332 }
333 
334 #define PASSWDPRINT	\
335 	printf("%s:%s:%u:%u:%s:%s:%s\n", \
336 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
337 	    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
338 
339 static int
340 passwd(int argc, char *argv[])
341 {
342 	int		i, rv = RV_OK;
343 	struct passwd	*pw;
344 
345 	setpassent(1);
346 	if (argc == 2) {
347 		while ((pw = getpwent()) != NULL)
348 			PASSWDPRINT;
349 	} else {
350 		for (i = 2; i < argc; i++) {
351 			const char	*err;
352 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
353 
354 			if (!err)
355 				pw = getpwuid((uid_t)id);
356 			else
357 				pw = getpwnam(argv[i]);
358 			if (pw != NULL)
359 				PASSWDPRINT;
360 			else {
361 				rv = RV_NOTFOUND;
362 				break;
363 			}
364 		}
365 	}
366 	endpwent();
367 	return rv;
368 }
369 
370 #define PROTOCOLSPRINT	\
371 	printfmtstrings(pe->p_aliases, "  ", " ", \
372 	    "%-16s  %5d", pe->p_name, pe->p_proto)
373 
374 static int
375 protocols(int argc, char *argv[])
376 {
377 	struct protoent	*pe;
378 	int		i, rv = RV_OK;
379 
380 	setprotoent(1);
381 	if (argc == 2) {
382 		while ((pe = getprotoent()) != NULL)
383 			PROTOCOLSPRINT;
384 	} else {
385 		for (i = 2; i < argc; i++) {
386 			const char	*err;
387 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
388 
389 			if (!err)
390 				pe = getprotobynumber((int)id);
391 			else
392 				pe = getprotobyname(argv[i]);
393 			if (pe != NULL)
394 				PROTOCOLSPRINT;
395 			else {
396 				rv = RV_NOTFOUND;
397 				break;
398 			}
399 		}
400 	}
401 	endprotoent();
402 	return rv;
403 }
404 
405 #define RPCPRINT	\
406 	printfmtstrings(re->r_aliases, "  ", " ", \
407 	    "%-16s  %6d", re->r_name, re->r_number)
408 
409 static int
410 rpc(int argc, char *argv[])
411 {
412 	struct rpcent	*re;
413 	int		i, rv = RV_OK;
414 
415 	setrpcent(1);
416 	if (argc == 2) {
417 		while ((re = getrpcent()) != NULL)
418 			RPCPRINT;
419 	} else {
420 		for (i = 2; i < argc; i++) {
421 			const char	*err;
422 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
423 
424 			if (!err)
425 				re = getrpcbynumber((int)id);
426 			else
427 				re = getrpcbyname(argv[i]);
428 			if (re != NULL)
429 				RPCPRINT;
430 			else {
431 				rv = RV_NOTFOUND;
432 				break;
433 			}
434 		}
435 	}
436 	endrpcent();
437 	return rv;
438 }
439 
440 #define SERVICESPRINT	\
441 	printfmtstrings(se->s_aliases, "  ", " ", \
442 	    "%-16s  %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
443 
444 static int
445 services(int argc, char *argv[])
446 {
447 	struct servent	*se;
448 	int		i, rv = RV_OK;
449 
450 	setservent(1);
451 	if (argc == 2) {
452 		while ((se = getservent()) != NULL)
453 			SERVICESPRINT;
454 	} else {
455 		for (i = 2; i < argc; i++) {
456 			const char	*err;
457 			long long	id;
458 			char *proto = strchr(argv[i], '/');
459 
460 			if (proto != NULL)
461 				*proto++ = '\0';
462 			id = strtonum(argv[i], 0, UINT_MAX, &err);
463 			if (!err)
464 				se = getservbyport(htons((u_short)id), proto);
465 			else
466 				se = getservbyname(argv[i], proto);
467 			if (se != NULL)
468 				SERVICESPRINT;
469 			else {
470 				rv = RV_NOTFOUND;
471 				break;
472 			}
473 		}
474 	}
475 	endservent();
476 	return rv;
477 }
478 
479 #define SHELLSPRINT	printf("%s\n", sh)
480 
481 static int
482 shells(int argc, char *argv[])
483 {
484 	const char	*sh;
485 	int		i, rv = RV_OK;
486 
487 	setusershell();
488 	if (argc == 2) {
489 		while ((sh = getusershell()) != NULL)
490 			SHELLSPRINT;
491 	} else {
492 		for (i = 2; i < argc; i++) {
493 			setusershell();
494 			while ((sh = getusershell()) != NULL) {
495 				if (strcmp(sh, argv[i]) == 0) {
496 					SHELLSPRINT;
497 					break;
498 				}
499 			}
500 			if (sh == NULL) {
501 				rv = RV_NOTFOUND;
502 				break;
503 			}
504 		}
505 	}
506 	endusershell();
507 	return rv;
508 }
509