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