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