xref: /openbsd/usr.bin/getent/getent.c (revision cecf84d4)
1 /*	$OpenBSD: getent.c,v 1.9 2015/01/16 06:40:08 deraadt 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	passwd(int, char *[]);
62 static int	protocols(int, char *[]);
63 static int	rpc(int, char *[]);
64 static int	services(int, char *[]);
65 static int	shells(int, char *[]);
66 extern char *__progname;
67 
68 enum {
69 	RV_OK		= 0,
70 	RV_USAGE	= 1,
71 	RV_NOTFOUND	= 2,
72 	RV_NOENUM	= 3
73 };
74 
75 static struct getentdb {
76 	const char	*name;
77 	int		(*fn)(int, char *[]);
78 } databases[] = {
79 	{	"ethers",	ethers,		},
80 	{	"group",	group,		},
81 	{	"hosts",	hosts,		},
82 	{	"passwd",	passwd,		},
83 	{	"protocols",	protocols,	},
84 	{	"rpc",		rpc,		},
85 	{	"services",	services,	},
86 	{	"shells",	shells,		},
87 
88 	{	NULL,		NULL,		},
89 };
90 
91 int
92 main(int argc, char *argv[])
93 {
94 	struct getentdb	*curdb;
95 
96 	if (argc < 2)
97 		usage();
98 	for (curdb = databases; curdb->name != NULL; curdb++) {
99 		if (strcmp(curdb->name, argv[1]) == 0) {
100 			exit(curdb->fn(argc, argv));
101 			break;
102 		}
103 	}
104 	fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]);
105 	return RV_USAGE;
106 }
107 
108 static int
109 usage(void)
110 {
111 	fprintf(stderr, "usage: %s database [key ...]\n", __progname);
112 	exit(RV_USAGE);
113 	/* NOTREACHED */
114 }
115 
116 /*
117  * printfmtstrings --
118  *	vprintf(format, ...),
119  *	then the aliases (beginning with prefix, separated by sep),
120  *	then a newline
121  */
122 static void
123 printfmtstrings(char *strings[], const char *prefix, const char *sep,
124 	const char *fmt, ...)
125 {
126 	va_list		ap;
127 	const char	*curpref;
128 	int		i;
129 
130 	va_start(ap, fmt);
131 	vprintf(fmt, ap);
132 	va_end(ap);
133 
134 	curpref = prefix;
135 	for (i = 0; strings[i] != NULL; i++) {
136 		printf("%s%s", curpref, strings[i]);
137 		curpref = sep;
138 	}
139 	printf("\n");
140 }
141 
142 #define ETHERSPRINT	printf("%-17s  %s\n", ether_ntoa(eap), hp)
143 
144 static int
145 ethers(int argc, char *argv[])
146 {
147 	char		hostname[HOST_NAME_MAX+1], *hp;
148 	int		i, rv = RV_OK;
149 	struct ether_addr ea, *eap;
150 
151 	if (argc == 2) {
152 		fprintf(stderr, "%s: Enumeration not supported on ethers\n",
153 		    __progname);
154 		rv = RV_NOENUM;
155 	} else {
156 		for (i = 2; i < argc; i++) {
157 			if ((eap = ether_aton(argv[i])) == NULL) {
158 				eap = &ea;
159 				hp = argv[i];
160 				if (ether_hostton(hp, eap) != 0) {
161 					rv = RV_NOTFOUND;
162 					break;
163 				}
164 			} else {
165 				hp = hostname;
166 				if (ether_ntohost(hp, eap) != 0) {
167 					rv = RV_NOTFOUND;
168 					break;
169 				}
170 			}
171 			ETHERSPRINT;
172 		}
173 	}
174 	return rv;
175 }
176 
177 #define GROUPPRINT	\
178 	printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
179 	    gr->gr_name, gr->gr_passwd, gr->gr_gid)
180 
181 static int
182 group(int argc, char *argv[])
183 {
184 	int		i, rv = RV_OK;
185 	struct group	*gr;
186 
187 	setgroupent(1);
188 	if (argc == 2) {
189 		while ((gr = getgrent()) != NULL)
190 			GROUPPRINT;
191 	} else {
192 		for (i = 2; i < argc; i++) {
193 			const char	*err;
194 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
195 
196 			if (!err)
197 				gr = getgrgid((gid_t)id);
198 			else
199 				gr = getgrnam(argv[i]);
200 			if (gr != NULL)
201 				GROUPPRINT;
202 			else {
203 				rv = RV_NOTFOUND;
204 				break;
205 			}
206 		}
207 	}
208 	endgrent();
209 	return rv;
210 }
211 
212 static void
213 hostsprint(const struct hostent *he)
214 {
215 	char	buf[INET6_ADDRSTRLEN];
216 
217 	if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
218 		strlcpy(buf, "# unknown", sizeof(buf));
219 	printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
220 }
221 static int
222 hostsaddrinfo(char* name)
223 {
224 	struct addrinfo	 hints, *res, *res0;
225 	void		*src;
226 	int		 rv;
227 	char		 buf[INET6_ADDRSTRLEN];
228 
229 	rv = RV_NOTFOUND;
230 	memset(buf, 0, sizeof(buf));
231 	memset(&hints, 0, sizeof(hints));
232 	hints.ai_family = PF_UNSPEC;
233 	hints.ai_socktype = SOCK_DGRAM;
234 
235 	if (getaddrinfo(name, NULL, &hints, &res0) == 0) {
236 		for (res = res0; res; res = res->ai_next) {
237 			switch (res->ai_family) {
238 			case AF_INET:
239 				src = &((struct sockaddr_in*)
240 				    res->ai_addr)->sin_addr;
241 				break;
242 			case AF_INET6:
243 				src = &((struct sockaddr_in6*)
244 				    res->ai_addr)->sin6_addr;
245 				break;
246 			default: /* not reached */
247 				src = NULL;
248 			}
249 			if (src==NULL || inet_ntop(res->ai_family, src, buf,
250 			    sizeof(buf)) == NULL)
251 				strlcpy(buf, "# unknown", sizeof(buf));
252 			else
253 				rv = RV_OK;
254 			printf("%-39s %s\n", buf, name);
255 		}
256 		freeaddrinfo(res0);
257 	}
258 
259 	return (rv);
260 }
261 
262 static int
263 hosts(int argc, char *argv[])
264 {
265 	char		addr[IN6ADDRSZ];
266 	int		i, rv = RV_OK;
267 	struct hostent	*he;
268 
269 	if (argc == 2) {
270 		fprintf(stderr, "%s: Enumeration not supported on hosts\n",
271 		    __progname);
272 		rv = RV_NOENUM;
273 	} else {
274 		for (i = 2; i < argc; i++) {
275 			he = NULL;
276 			if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
277 				he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
278 			else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
279 				he = gethostbyaddr(addr, INADDRSZ, AF_INET);
280 			if (he != NULL)
281 				hostsprint(he);
282 			else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
283 				break;
284 		}
285 	}
286 	return rv;
287 }
288 
289 #define PASSWDPRINT	\
290 	printf("%s:%s:%u:%u:%s:%s:%s\n", \
291 	    pw->pw_name, pw->pw_passwd, pw->pw_uid, \
292 	    pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
293 
294 static int
295 passwd(int argc, char *argv[])
296 {
297 	int		i, rv = RV_OK;
298 	struct passwd	*pw;
299 
300 	setpassent(1);
301 	if (argc == 2) {
302 		while ((pw = getpwent()) != NULL)
303 			PASSWDPRINT;
304 	} else {
305 		for (i = 2; i < argc; i++) {
306 			const char	*err;
307 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
308 
309 			if (!err)
310 				pw = getpwuid((uid_t)id);
311 			else
312 				pw = getpwnam(argv[i]);
313 			if (pw != NULL)
314 				PASSWDPRINT;
315 			else {
316 				rv = RV_NOTFOUND;
317 				break;
318 			}
319 		}
320 	}
321 	endpwent();
322 	return rv;
323 }
324 
325 #define PROTOCOLSPRINT	\
326 	printfmtstrings(pe->p_aliases, "  ", " ", \
327 	    "%-16s  %5d", pe->p_name, pe->p_proto)
328 
329 static int
330 protocols(int argc, char *argv[])
331 {
332 	struct protoent	*pe;
333 	int		i, rv = RV_OK;
334 
335 	setprotoent(1);
336 	if (argc == 2) {
337 		while ((pe = getprotoent()) != NULL)
338 			PROTOCOLSPRINT;
339 	} else {
340 		for (i = 2; i < argc; i++) {
341 			const char	*err;
342 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
343 
344 			if (!err)
345 				pe = getprotobynumber((int)id);
346 			else
347 				pe = getprotobyname(argv[i]);
348 			if (pe != NULL)
349 				PROTOCOLSPRINT;
350 			else {
351 				rv = RV_NOTFOUND;
352 				break;
353 			}
354 		}
355 	}
356 	endprotoent();
357 	return rv;
358 }
359 
360 #define RPCPRINT	\
361 	printfmtstrings(re->r_aliases, "  ", " ", \
362 	    "%-16s  %6d", re->r_name, re->r_number)
363 
364 static int
365 rpc(int argc, char *argv[])
366 {
367 	struct rpcent	*re;
368 	int		i, rv = RV_OK;
369 
370 	setrpcent(1);
371 	if (argc == 2) {
372 		while ((re = getrpcent()) != NULL)
373 			RPCPRINT;
374 	} else {
375 		for (i = 2; i < argc; i++) {
376 			const char	*err;
377 			long long id = strtonum(argv[i], 0, UINT_MAX, &err);
378 
379 			if (!err)
380 				re = getrpcbynumber((int)id);
381 			else
382 				re = getrpcbyname(argv[i]);
383 			if (re != NULL)
384 				RPCPRINT;
385 			else {
386 				rv = RV_NOTFOUND;
387 				break;
388 			}
389 		}
390 	}
391 	endrpcent();
392 	return rv;
393 }
394 
395 #define SERVICESPRINT	\
396 	printfmtstrings(se->s_aliases, "  ", " ", \
397 	    "%-16s  %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
398 
399 static int
400 services(int argc, char *argv[])
401 {
402 	struct servent	*se;
403 	int		i, rv = RV_OK;
404 
405 	setservent(1);
406 	if (argc == 2) {
407 		while ((se = getservent()) != NULL)
408 			SERVICESPRINT;
409 	} else {
410 		for (i = 2; i < argc; i++) {
411 			const char	*err;
412 			long long	id;
413 			char *proto = strchr(argv[i], '/');
414 
415 			if (proto != NULL)
416 				*proto++ = '\0';
417 			id = strtonum(argv[i], 0, UINT_MAX, &err);
418 			if (!err)
419 				se = getservbyport(htons((u_short)id), proto);
420 			else
421 				se = getservbyname(argv[i], proto);
422 			if (se != NULL)
423 				SERVICESPRINT;
424 			else {
425 				rv = RV_NOTFOUND;
426 				break;
427 			}
428 		}
429 	}
430 	endservent();
431 	return rv;
432 }
433 
434 #define SHELLSPRINT	printf("%s\n", sh)
435 
436 static int
437 shells(int argc, char *argv[])
438 {
439 	const char	*sh;
440 	int		i, rv = RV_OK;
441 
442 	setusershell();
443 	if (argc == 2) {
444 		while ((sh = getusershell()) != NULL)
445 			SHELLSPRINT;
446 	} else {
447 		for (i = 2; i < argc; i++) {
448 			setusershell();
449 			while ((sh = getusershell()) != NULL) {
450 				if (strcmp(sh, argv[i]) == 0) {
451 					SHELLSPRINT;
452 					break;
453 				}
454 			}
455 			if (sh == NULL) {
456 				rv = RV_NOTFOUND;
457 				break;
458 			}
459 		}
460 	}
461 	endusershell();
462 	return rv;
463 }
464