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