xref: /netbsd-src/usr.bin/getent/getent.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Luke Mewburn.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $");
42 #endif /* not lint */
43 
44 #include <sys/socket.h>
45 
46 #include <assert.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <grp.h>
50 #include <limits.h>
51 #include <netdb.h>
52 #include <pwd.h>
53 #include <stdio.h>
54 #include <stdarg.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 #include <arpa/inet.h>
60 #include <arpa/nameser.h>
61 
62 #include <net/if.h>
63 #include <net/if_ether.h>
64 
65 #include <netinet/in.h>		/* for INET6_ADDRSTRLEN */
66 
67 #include <rpc/rpcent.h>
68 
69 static int	usage(void);
70 static int	parsenum(const char *, unsigned long *);
71 static int	ethers(int, char *[]);
72 static int	group(int, char *[]);
73 static int	hosts(int, char *[]);
74 static int	networks(int, char *[]);
75 static int	passwd(int, char *[]);
76 static int	protocols(int, char *[]);
77 static int	rpc(int, char *[]);
78 static int	services(int, char *[]);
79 static int	shells(int, char *[]);
80 
81 enum {
82 	RV_OK		= 0,
83 	RV_USAGE	= 1,
84 	RV_NOTFOUND	= 2,
85 	RV_NOENUM	= 3,
86 };
87 
88 static struct getentdb {
89 	const char	*name;
90 	int		(*callback)(int, char *[]);
91 } databases[] = {
92 	{	"ethers",	ethers,		},
93 	{	"group",	group,		},
94 	{	"hosts",	hosts,		},
95 	{	"networks",	networks,	},
96 	{	"passwd",	passwd,		},
97 	{	"protocols",	protocols,	},
98 	{	"rpc",		rpc,		},
99 	{	"services",	services,	},
100 	{	"shells",	shells,		},
101 
102 	{	NULL,		NULL,		},
103 };
104 
105 
106 int
107 main(int argc, char *argv[])
108 {
109 	struct getentdb	*curdb;
110 
111 	setprogname(argv[0]);
112 
113 	if (argc < 2)
114 		usage();
115 	for (curdb = databases; curdb->name != NULL; curdb++) {
116 		if (strcmp(curdb->name, argv[1]) == 0) {
117 			exit(curdb->callback(argc, argv));
118 			break;
119 		}
120 	}
121 	fprintf(stderr, "Unknown database: %s\n", argv[1]);
122 	usage();
123 	/* NOTREACHED */
124 	return RV_USAGE;
125 }
126 
127 static int
128 usage(void)
129 {
130 	struct getentdb	*curdb;
131 
132 	fprintf(stderr, "Usage: %s database [key ...]\n",
133 	    getprogname());
134 	fprintf(stderr, "       database may be one of:\n\t");
135 	for (curdb = databases; curdb->name != NULL; curdb++) {
136 		fprintf(stderr, " %s", curdb->name);
137 	}
138 	fprintf(stderr, "\n");
139 	exit(RV_USAGE);
140 	/* NOTREACHED */
141 }
142 
143 static int
144 parsenum(const char *word, unsigned long *result)
145 {
146 	unsigned long	num;
147 	char		*ep;
148 
149 	assert(word != NULL);
150 	assert(result != NULL);
151 
152 	if (!isdigit((unsigned char)word[0]))
153 		return 0;
154 	errno = 0;
155 	num = strtoul(word, &ep, 10);
156 	if (num == ULONG_MAX && errno == ERANGE)
157 		return 0;
158 	if (*ep != '\0')
159 		return 0;
160 	*result = num;
161 	return 1;
162 }
163 
164 /*
165  * printfmtstrings --
166  *	vprintf(format, ...),
167  *	then the aliases (beginning with prefix, separated by sep),
168  *	then a newline
169  */
170 static void
171 printfmtstrings(char *strings[], const char *prefix, const char *sep,
172 	const char *fmt, ...)
173 {
174 	va_list		ap;
175 	const char	*curpref;
176 	int		i;
177 
178 	va_start(ap, fmt);
179 	vprintf(fmt, ap);
180 
181 	curpref = prefix;
182 	for (i = 0; strings[i] != NULL; i++) {
183 		printf("%s%s", curpref, strings[i]);
184 		curpref = sep;
185 	}
186 	printf("\n");
187 }
188 
189 
190 		/*
191 		 * ethers
192 		 */
193 
194 static int
195 ethers(int argc, char *argv[])
196 {
197 	char		hostname[MAXHOSTNAMELEN + 1], *hp;
198 	struct ether_addr ea, *eap;
199 	int		i, rv;
200 
201 	assert(argc > 1);
202 	assert(argv != NULL);
203 
204 #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
205 
206 	rv = RV_OK;
207 	if (argc == 2) {
208 		fprintf(stderr, "Enumeration not supported on ethers\n");
209 		rv = RV_NOENUM;
210 	} else {
211 		for (i = 2; i < argc; i++) {
212 			if ((eap = ether_aton(argv[i])) == NULL) {
213 				eap = &ea;
214 				hp = argv[i];
215 				if (ether_hostton(hp, eap) != 0) {
216 					rv = RV_NOTFOUND;
217 					break;
218 				}
219 			} else {
220 				hp = hostname;
221 				if (ether_ntohost(hp, eap) != 0) {
222 					rv = RV_NOTFOUND;
223 					break;
224 				}
225 			}
226 			ETHERSPRINT;
227 		}
228 	}
229 	return rv;
230 }
231 
232 		/*
233 		 * group
234 		 */
235 
236 static int
237 group(int argc, char *argv[])
238 {
239 	struct group	*gr;
240 	unsigned long	id;
241 	int		i, rv;
242 
243 	assert(argc > 1);
244 	assert(argv != NULL);
245 
246 #define GROUPPRINT	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
247 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
248 
249 	setgroupent(1);
250 	rv = RV_OK;
251 	if (argc == 2) {
252 		while ((gr = getgrent()) != NULL)
253 			GROUPPRINT;
254 	} else {
255 		for (i = 2; i < argc; i++) {
256 			if (parsenum(argv[i], &id))
257 				gr = getgrgid((gid_t)id);
258 			else
259 				gr = getgrnam(argv[i]);
260 			if (gr != NULL)
261 				GROUPPRINT;
262 			else {
263 				rv = RV_NOTFOUND;
264 				break;
265 			}
266 		}
267 	}
268 	endgrent();
269 	return rv;
270 }
271 
272 
273 		/*
274 		 * hosts
275 		 */
276 
277 static void
278 hostsprint(const struct hostent *he)
279 {
280 	char	buf[INET6_ADDRSTRLEN];
281 
282 	assert(he != NULL);
283 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
284 		strlcpy(buf, "# unknown", sizeof(buf));
285 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
286 }
287 
288 static int
289 hosts(int argc, char *argv[])
290 {
291 	struct hostent	*he;
292 	char		addr[IN6ADDRSZ];
293 	int		i, rv;
294 
295 	assert(argc > 1);
296 	assert(argv != NULL);
297 
298 	sethostent(1);
299 	rv = RV_OK;
300 	if (argc == 2) {
301 		while ((he = gethostent()) != NULL)
302 			hostsprint(he);
303 	} else {
304 		for (i = 2; i < argc; i++) {
305 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
306 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
307 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
308 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
309 			else
310 				he = gethostbyname(argv[i]);
311 			if (he != NULL)
312 				hostsprint(he);
313 			else {
314 				rv = RV_NOTFOUND;
315 				break;
316 			}
317 		}
318 	}
319 	endhostent();
320 	return rv;
321 }
322 
323 
324 		/*
325 		 * networks
326 		 */
327 
328 static void
329 networksprint(const struct netent *ne)
330 {
331 	char		buf[INET6_ADDRSTRLEN];
332 	struct	in_addr	ianet;
333 
334 	assert(ne != NULL);
335 	ianet = inet_makeaddr(ne->n_net, 0);
336 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
337 		strlcpy(buf, "# unknown", sizeof(buf));
338 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
339 }
340 
341 static int
342 networks(int argc, char *argv[])
343 {
344 	struct netent	*ne;
345 	in_addr_t	net;
346 	int		i, rv;
347 
348 	assert(argc > 1);
349 	assert(argv != NULL);
350 
351 	setnetent(1);
352 	rv = RV_OK;
353 	if (argc == 2) {
354 		while ((ne = getnetent()) != NULL)
355 			networksprint(ne);
356 	} else {
357 		for (i = 2; i < argc; i++) {
358 			net = inet_network(argv[i]);
359 			if (net != INADDR_NONE)
360 				ne = getnetbyaddr(net, AF_INET);
361 			else
362 				ne = getnetbyname(argv[i]);
363 			if (ne != NULL)
364 				networksprint(ne);
365 			else {
366 				rv = RV_NOTFOUND;
367 				break;
368 			}
369 		}
370 	}
371 	endnetent();
372 	return rv;
373 }
374 
375 
376 		/*
377 		 * passwd
378 		 */
379 
380 static int
381 passwd(int argc, char *argv[])
382 {
383 	struct passwd	*pw;
384 	unsigned long	id;
385 	int		i, rv;
386 
387 	assert(argc > 1);
388 	assert(argv != NULL);
389 
390 #define PASSWDPRINT	printf("%s:%s:%u:%u:%s:%s:%s\n", \
391 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
392 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
393 
394 	setpassent(1);
395 	rv = RV_OK;
396 	if (argc == 2) {
397 		while ((pw = getpwent()) != NULL)
398 			PASSWDPRINT;
399 	} else {
400 		for (i = 2; i < argc; i++) {
401 			if (parsenum(argv[i], &id))
402 				pw = getpwuid((uid_t)id);
403 			else
404 				pw = getpwnam(argv[i]);
405 			if (pw != NULL)
406 				PASSWDPRINT;
407 			else {
408 				rv = RV_NOTFOUND;
409 				break;
410 			}
411 		}
412 	}
413 	endpwent();
414 	return rv;
415 }
416 
417 
418 		/*
419 		 * protocols
420 		 */
421 
422 static int
423 protocols(int argc, char *argv[])
424 {
425 	struct protoent	*pe;
426 	unsigned long	id;
427 	int		i, rv;
428 
429 	assert(argc > 1);
430 	assert(argv != NULL);
431 
432 #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
433 			    "%-16s  %5d", pe->p_name, pe->p_proto)
434 
435 	setprotoent(1);
436 	rv = RV_OK;
437 	if (argc == 2) {
438 		while ((pe = getprotoent()) != NULL)
439 			PROTOCOLSPRINT;
440 	} else {
441 		for (i = 2; i < argc; i++) {
442 			if (parsenum(argv[i], &id))
443 				pe = getprotobynumber((int)id);
444 			else
445 				pe = getprotobyname(argv[i]);
446 			if (pe != NULL)
447 				PROTOCOLSPRINT;
448 			else {
449 				rv = RV_NOTFOUND;
450 				break;
451 			}
452 		}
453 	}
454 	endprotoent();
455 	return rv;
456 }
457 
458 		/*
459 		 * rpc
460 		 */
461 
462 static int
463 rpc(int argc, char *argv[])
464 {
465 	struct rpcent	*re;
466 	unsigned long	id;
467 	int		i, rv;
468 
469 	assert(argc > 1);
470 	assert(argv != NULL);
471 
472 #define RPCPRINT	printfmtstrings(re->r_aliases, "  ", " ", \
473 				"%-16s  %6d", \
474 				re->r_name, re->r_number)
475 
476 	setrpcent(1);
477 	rv = RV_OK;
478 	if (argc == 2) {
479 		while ((re = getrpcent()) != NULL)
480 			RPCPRINT;
481 	} else {
482 		for (i = 2; i < argc; i++) {
483 			if (parsenum(argv[i], &id))
484 				re = getrpcbynumber((int)id);
485 			else
486 				re = getrpcbyname(argv[i]);
487 			if (re != NULL)
488 				RPCPRINT;
489 			else {
490 				rv = RV_NOTFOUND;
491 				break;
492 			}
493 		}
494 	}
495 	endrpcent();
496 	return rv;
497 }
498 
499 		/*
500 		 * services
501 		 */
502 
503 static int
504 services(int argc, char *argv[])
505 {
506 	struct servent	*se;
507 	unsigned long	id;
508 	char		*proto;
509 	int		i, rv;
510 
511 	assert(argc > 1);
512 	assert(argv != NULL);
513 
514 #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
515 			    "%-16s  %5d/%s", \
516 			    se->s_name, ntohs(se->s_port), se->s_proto)
517 
518 	setservent(1);
519 	rv = RV_OK;
520 	if (argc == 2) {
521 		while ((se = getservent()) != NULL)
522 			SERVICESPRINT;
523 	} else {
524 		for (i = 2; i < argc; i++) {
525 			proto = strchr(argv[i], '/');
526 			if (proto != NULL)
527 				*proto++ = '\0';
528 			if (parsenum(argv[i], &id))
529 				se = getservbyport((int)id, proto);
530 			else
531 				se = getservbyname(argv[i], proto);
532 			if (se != NULL)
533 				SERVICESPRINT;
534 			else {
535 				rv = RV_NOTFOUND;
536 				break;
537 			}
538 		}
539 	}
540 	endservent();
541 	return rv;
542 }
543 
544 
545 		/*
546 		 * shells
547 		 */
548 
549 static int
550 shells(int argc, char *argv[])
551 {
552 	const char	*sh;
553 	int		i, rv;
554 
555 	assert(argc > 1);
556 	assert(argv != NULL);
557 
558 #define SHELLSPRINT	printf("%s\n", sh)
559 
560 	setusershell();
561 	rv = RV_OK;
562 	if (argc == 2) {
563 		while ((sh = getusershell()) != NULL)
564 			SHELLSPRINT;
565 	} else {
566 		for (i = 2; i < argc; i++) {
567 			setusershell();
568 			while ((sh = getusershell()) != NULL) {
569 				if (strcmp(sh, argv[i]) == 0) {
570 					SHELLSPRINT;
571 					break;
572 				}
573 			}
574 			if (sh == NULL) {
575 				rv = RV_NOTFOUND;
576 				break;
577 			}
578 		}
579 	}
580 	endusershell();
581 	return rv;
582 }
583