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