Annotation of src/usr.bin/getent/getent.c, Revision 1.21
1.21 ! kn 1: /* $OpenBSD: getent.c,v 1.20 2018/09/26 16:39:19 kn 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.20 kn 193: struct group *gr;
194: const char *err;
195: gid_t gid;
1.2 deraadt 196: int i, rv = RV_OK;
1.1 otto 197:
198: setgroupent(1);
199: if (argc == 2) {
200: while ((gr = getgrent()) != NULL)
201: GROUPPRINT;
202: } else {
203: for (i = 2; i < argc; i++) {
1.21 ! kn 204: if ((gr = getgrnam(argv[i])) == NULL) {
! 205: gid = strtonum(argv[i], 0, GID_MAX, &err);
! 206: if (err == NULL)
! 207: gr = getgrgid(gid);
! 208: }
1.1 otto 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));
1.19 kn 228: printfmtstrings(he->h_aliases, " ", " ", "%-39s %s", buf, he->h_name);
1.1 otto 229: }
1.6 florian 230: static int
1.18 kn 231: hostsaddrinfo(const char *name)
1.6 florian 232: {
233: struct addrinfo hints, *res, *res0;
1.18 kn 234: char buf[INET6_ADDRSTRLEN];
1.6 florian 235: int rv;
236:
237: rv = RV_NOTFOUND;
238: memset(buf, 0, sizeof(buf));
239: memset(&hints, 0, sizeof(hints));
1.18 kn 240: hints.ai_family = AF_UNSPEC;
1.6 florian 241: hints.ai_socktype = SOCK_DGRAM;
242:
1.18 kn 243: if (getaddrinfo(name, NULL, &hints, &res0) != 0)
244: return (rv);
245: for (res = res0; res; res = res->ai_next) {
246: if ((res->ai_family != AF_INET6 && res->ai_family != AF_INET) ||
247: getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf),
248: NULL, 0, NI_NUMERICHOST) != 0)
249: strlcpy(buf, "# unknown", sizeof(buf));
250: else
251: rv = RV_OK;
252: printf("%-39s %s\n", buf, name);
1.6 florian 253: }
1.18 kn 254: freeaddrinfo(res0);
1.6 florian 255:
256: return (rv);
257: }
1.1 otto 258:
259: static int
260: hosts(int argc, char *argv[])
261: {
1.2 deraadt 262: char addr[IN6ADDRSZ];
263: int i, rv = RV_OK;
1.1 otto 264: struct hostent *he;
265:
266: if (argc == 2) {
1.7 schwarze 267: fprintf(stderr, "%s: Enumeration not supported on hosts\n",
268: __progname);
269: rv = RV_NOENUM;
1.1 otto 270: } else {
271: for (i = 2; i < argc; i++) {
1.6 florian 272: he = NULL;
1.1 otto 273: if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
274: he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
275: else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
276: he = gethostbyaddr(addr, INADDRSZ, AF_INET);
277: if (he != NULL)
278: hostsprint(he);
1.6 florian 279: else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
1.1 otto 280: break;
281: }
282: }
283: return rv;
284: }
285:
1.2 deraadt 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)
1.1 otto 290:
291: static int
292: passwd(int argc, char *argv[])
293: {
1.20 kn 294: struct passwd *pw;
295: const char *err;
296: uid_t uid;
1.2 deraadt 297: int i, rv = RV_OK;
1.1 otto 298:
299: setpassent(1);
300: if (argc == 2) {
301: while ((pw = getpwent()) != NULL)
302: PASSWDPRINT;
303: } else {
304: for (i = 2; i < argc; i++) {
1.21 ! kn 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: }
1.1 otto 310: if (pw != NULL)
311: PASSWDPRINT;
312: else {
313: rv = RV_NOTFOUND;
314: break;
315: }
316: }
317: }
318: endpwent();
319: return rv;
320: }
321:
1.2 deraadt 322: #define PROTOCOLSPRINT \
323: printfmtstrings(pe->p_aliases, " ", " ", \
324: "%-16s %5d", pe->p_name, pe->p_proto)
1.1 otto 325:
326: static int
327: protocols(int argc, char *argv[])
328: {
329: struct protoent *pe;
1.20 kn 330: const char *err;
331: int proto;
1.2 deraadt 332: int i, rv = RV_OK;
1.1 otto 333:
334: setprotoent(1);
335: if (argc == 2) {
336: while ((pe = getprotoent()) != NULL)
337: PROTOCOLSPRINT;
338: } else {
339: for (i = 2; i < argc; i++) {
1.20 kn 340: proto = strtonum(argv[i], 0, INT_MAX, &err);
1.2 deraadt 341: if (!err)
1.20 kn 342: pe = getprotobynumber(proto);
1.1 otto 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:
1.2 deraadt 357: #define RPCPRINT \
358: printfmtstrings(re->r_aliases, " ", " ", \
359: "%-16s %6d", re->r_name, re->r_number)
1.1 otto 360:
361: static int
362: rpc(int argc, char *argv[])
363: {
364: struct rpcent *re;
1.20 kn 365: const char *err;
366: int rpc;
1.2 deraadt 367: int i, rv = RV_OK;
1.1 otto 368:
369: setrpcent(1);
370: if (argc == 2) {
371: while ((re = getrpcent()) != NULL)
372: RPCPRINT;
373: } else {
374: for (i = 2; i < argc; i++) {
1.20 kn 375: rpc = strtonum(argv[i], 0, INT_MAX, &err);
1.2 deraadt 376: if (!err)
1.20 kn 377: re = getrpcbynumber(rpc);
1.1 otto 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:
1.2 deraadt 392: #define SERVICESPRINT \
393: printfmtstrings(se->s_aliases, " ", " ", \
394: "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
1.1 otto 395:
396: static int
397: services(int argc, char *argv[])
398: {
399: struct servent *se;
1.20 kn 400: const char *err;
401: char *proto;
402: in_port_t port;
1.2 deraadt 403: int i, rv = RV_OK;
1.1 otto 404:
405: setservent(1);
406: if (argc == 2) {
407: while ((se = getservent()) != NULL)
408: SERVICESPRINT;
409: } else {
410: for (i = 2; i < argc; i++) {
1.20 kn 411: if ((proto = strchr(argv[i], '/')) != NULL)
1.1 otto 412: *proto++ = '\0';
1.20 kn 413: port = strtonum(argv[i], 0, IPPORT_HILASTAUTO, &err);
1.2 deraadt 414: if (!err)
1.20 kn 415: se = getservbyport(htons(port), proto);
1.1 otto 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:
1.14 jca 430: #define SHELLSPRINT printf("%s\n", sh)
431:
1.1 otto 432: static int
433: shells(int argc, char *argv[])
434: {
435: const char *sh;
1.2 deraadt 436: int i, rv = RV_OK;
1.1 otto 437:
438: setusershell();
439: if (argc == 2) {
440: while ((sh = getusershell()) != NULL)
1.14 jca 441: SHELLSPRINT;
1.1 otto 442: } else {
443: for (i = 2; i < argc; i++) {
444: setusershell();
445: while ((sh = getusershell()) != NULL) {
446: if (strcmp(sh, argv[i]) == 0) {
1.14 jca 447: SHELLSPRINT;
1.1 otto 448: break;
449: }
450: }
451: if (sh == NULL) {
452: rv = RV_NOTFOUND;
453: break;
454: }
455: }
456: }
457: endusershell();
458: return rv;
459: }