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