xref: /netbsd-src/usr.bin/getent/getent.c (revision db6316d1518382eecd2fdbe55a1205e0620a1b35)
1 /*	$NetBSD: getent.c,v 1.5 2004/11/29 05:02:40 lukem 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.5 2004/11/29 05:02:40 lukem 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 static int	usage(void);
65 static int	parsenum(const char *, unsigned long *);
66 static int	group(int, char *[]);
67 static int	hosts(int, char *[]);
68 static int	networks(int, char *[]);
69 static int	passwd(int, char *[]);
70 static int	protocols(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 	{	"group",	group,		},
86 	{	"hosts",	hosts,		},
87 	{	"networks",	networks,	},
88 	{	"passwd",	passwd,		},
89 	{	"protocols",	protocols,	},
90 	{	"services",	services,	},
91 	{	"shells",	shells,		},
92 
93 	{	NULL,		NULL,		},
94 };
95 
96 
97 int
98 main(int argc, char *argv[])
99 {
100 	struct getentdb	*curdb;
101 
102 	setprogname(argv[0]);
103 
104 	if (argc < 2)
105 		usage();
106 	for (curdb = databases; curdb->name != NULL; curdb++) {
107 		if (strcmp(curdb->name, argv[1]) == 0) {
108 			exit(curdb->callback(argc, argv));
109 			break;
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 }
179 
180 
181 		/*
182 		 * group
183 		 */
184 
185 static int
186 group(int argc, char *argv[])
187 {
188 	struct group	*gr;
189 	unsigned long	id;
190 	int		i, rv;
191 
192 	assert(argc > 1);
193 	assert(argv != NULL);
194 
195 #define GROUPPRINT	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
196 			    gr->gr_name, gr->gr_passwd, gr->gr_gid)
197 
198 	setgroupent(1);
199 	rv = RV_OK;
200 	if (argc == 2) {
201 		while ((gr = getgrent()) != NULL)
202 			GROUPPRINT;
203 	} else {
204 		for (i = 2; i < argc; i++) {
205 			if (parsenum(argv[i], &id))
206 				gr = getgrgid((gid_t)id);
207 			else
208 				gr = getgrnam(argv[i]);
209 			if (gr != NULL)
210 				GROUPPRINT;
211 			else {
212 				rv = RV_NOTFOUND;
213 				break;
214 			}
215 		}
216 	}
217 	endgrent();
218 	return rv;
219 }
220 
221 
222 		/*
223 		 * hosts
224 		 */
225 
226 static void
227 hostsprint(const struct hostent *he)
228 {
229 	char	buf[INET6_ADDRSTRLEN];
230 
231 	assert(he != NULL);
232 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
233 		strlcpy(buf, "# unknown", sizeof(buf));
234 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
235 }
236 
237 static int
238 hosts(int argc, char *argv[])
239 {
240 	struct hostent	*he;
241 	char		addr[IN6ADDRSZ];
242 	int		i, rv;
243 
244 	assert(argc > 1);
245 	assert(argv != NULL);
246 
247 	sethostent(1);
248 	rv = RV_OK;
249 	if (argc == 2) {
250 		while ((he = gethostent()) != NULL)
251 			hostsprint(he);
252 	} else {
253 		for (i = 2; i < argc; i++) {
254 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
255 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
256 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
257 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
258 			else
259 				he = gethostbyname(argv[i]);
260 			if (he != NULL)
261 				hostsprint(he);
262 			else {
263 				rv = RV_NOTFOUND;
264 				break;
265 			}
266 		}
267 	}
268 	endhostent();
269 	return rv;
270 }
271 
272 
273 		/*
274 		 * networks
275 		 */
276 
277 static void
278 networksprint(const struct netent *ne)
279 {
280 	char		buf[INET6_ADDRSTRLEN];
281 	struct	in_addr	ianet;
282 
283 	assert(ne != NULL);
284 	ianet = inet_makeaddr(ne->n_net, 0);
285 	if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
286 		strlcpy(buf, "# unknown", sizeof(buf));
287 	printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
288 }
289 
290 static int
291 networks(int argc, char *argv[])
292 {
293 	struct netent	*ne;
294 	in_addr_t	net;
295 	int		i, rv;
296 
297 	assert(argc > 1);
298 	assert(argv != NULL);
299 
300 	setnetent(1);
301 	rv = RV_OK;
302 	if (argc == 2) {
303 		while ((ne = getnetent()) != NULL)
304 			networksprint(ne);
305 	} else {
306 		for (i = 2; i < argc; i++) {
307 			net = inet_network(argv[i]);
308 			if (net != INADDR_NONE)
309 				ne = getnetbyaddr(net, AF_INET);
310 			else
311 				ne = getnetbyname(argv[i]);
312 			if (ne != NULL)
313 				networksprint(ne);
314 			else {
315 				rv = RV_NOTFOUND;
316 				break;
317 			}
318 		}
319 	}
320 	endnetent();
321 	return rv;
322 }
323 
324 
325 		/*
326 		 * passwd
327 		 */
328 
329 static int
330 passwd(int argc, char *argv[])
331 {
332 	struct passwd	*pw;
333 	unsigned long	id;
334 	int		i, rv;
335 
336 	assert(argc > 1);
337 	assert(argv != NULL);
338 
339 #define PASSWDPRINT	printf("%s:%s:%u:%u:%s:%s:%s\n", \
340 			    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
341 			    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
342 
343 	setpassent(1);
344 	rv = RV_OK;
345 	if (argc == 2) {
346 		while ((pw = getpwent()) != NULL)
347 			PASSWDPRINT;
348 	} else {
349 		for (i = 2; i < argc; i++) {
350 			if (parsenum(argv[i], &id))
351 				pw = getpwuid((uid_t)id);
352 			else
353 				pw = getpwnam(argv[i]);
354 			if (pw != NULL)
355 				PASSWDPRINT;
356 			else {
357 				rv = RV_NOTFOUND;
358 				break;
359 			}
360 		}
361 	}
362 	endpwent();
363 	return rv;
364 }
365 
366 
367 		/*
368 		 * protocols
369 		 */
370 
371 static int
372 protocols(int argc, char *argv[])
373 {
374 	struct protoent	*pe;
375 	unsigned long	id;
376 	int		i, rv;
377 
378 	assert(argc > 1);
379 	assert(argv != NULL);
380 
381 #define PROTOCOLSPRINT	printfmtstrings(pe->p_aliases, "  ", " ", \
382 			    "%-16s  %5d", pe->p_name, pe->p_proto)
383 
384 	setprotoent(1);
385 	rv = RV_OK;
386 	if (argc == 2) {
387 		while ((pe = getprotoent()) != NULL)
388 			PROTOCOLSPRINT;
389 	} else {
390 		for (i = 2; i < argc; i++) {
391 			if (parsenum(argv[i], &id))
392 				pe = getprotobynumber((int)id);
393 			else
394 				pe = getprotobyname(argv[i]);
395 			if (pe != NULL)
396 				PROTOCOLSPRINT;
397 			else {
398 				rv = RV_NOTFOUND;
399 				break;
400 			}
401 		}
402 	}
403 	endprotoent();
404 	return rv;
405 }
406 
407 
408 		/*
409 		 * services
410 		 */
411 
412 static int
413 services(int argc, char *argv[])
414 {
415 	struct servent	*se;
416 	unsigned long	id;
417 	char		*proto;
418 	int		i, rv;
419 
420 	assert(argc > 1);
421 	assert(argv != NULL);
422 
423 #define SERVICESPRINT	printfmtstrings(se->s_aliases, "  ", " ", \
424 			    "%-16s  %5d/%s", \
425 			    se->s_name, ntohs(se->s_port), se->s_proto)
426 
427 	setservent(1);
428 	rv = RV_OK;
429 	if (argc == 2) {
430 		while ((se = getservent()) != NULL)
431 			SERVICESPRINT;
432 	} else {
433 		for (i = 2; i < argc; i++) {
434 			proto = strchr(argv[i], '/');
435 			if (proto != NULL)
436 				*proto++ = '\0';
437 			if (parsenum(argv[i], &id))
438 				se = getservbyport((int)id, proto);
439 			else
440 				se = getservbyname(argv[i], proto);
441 			if (se != NULL)
442 				SERVICESPRINT;
443 			else {
444 				rv = RV_NOTFOUND;
445 				break;
446 			}
447 		}
448 	}
449 	endservent();
450 	return rv;
451 }
452 
453 
454 		/*
455 		 * shells
456 		 */
457 
458 static int
459 shells(int argc, char *argv[])
460 {
461 	const char	*sh;
462 	int		i, rv;
463 
464 	assert(argc > 1);
465 	assert(argv != NULL);
466 
467 #define SHELLSPRINT	printf("%s\n", sh)
468 
469 	setusershell();
470 	rv = RV_OK;
471 	if (argc == 2) {
472 		while ((sh = getusershell()) != NULL)
473 			SHELLSPRINT;
474 	} else {
475 		for (i = 2; i < argc; i++) {
476 			setusershell();
477 			while ((sh = getusershell()) != NULL) {
478 				if (strcmp(sh, argv[i]) == 0) {
479 					SHELLSPRINT;
480 					break;
481 				}
482 			}
483 			if (sh == NULL) {
484 				rv = RV_NOTFOUND;
485 				break;
486 			}
487 		}
488 	}
489 	endusershell();
490 	return rv;
491 }
492