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