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