Annotation of src/usr.bin/getent/getent.c, Revision 1.11
1.11 ! deraadt 1: /* $OpenBSD: getent.c,v 1.10 2015/10/10 05:26:57 doug 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.1 otto 80: } databases[] = {
1.10 doug 81: { "ethers", ethers, "stdio rpath" },
82: { "group", group, "stdio rpath" },
83: { "hosts", hosts, "stdio dns" },
84: { "passwd", passwd, "stdio rpath" },
85: { "protocols", protocols, "stdio rpath" },
86: { "rpc", rpc, "stdio rpath" },
87: { "services", services, "stdio rpath" },
88: { "shells", shells, "stdio rpath" },
1.1 otto 89:
1.10 doug 90: { NULL, NULL, },
1.1 otto 91: };
92:
93: int
94: main(int argc, char *argv[])
95: {
96: struct getentdb *curdb;
97:
1.11 ! deraadt 98: if (pledge("stdio dns rpath getpw", NULL) == -1)
1.10 doug 99: err(1, "pledge");
100:
1.1 otto 101: if (argc < 2)
102: usage();
103: for (curdb = databases; curdb->name != NULL; curdb++) {
104: if (strcmp(curdb->name, argv[1]) == 0) {
1.10 doug 105: if (pledge(curdb->pledge, NULL) == -1)
106: err(1, "pledge");
107:
1.2 deraadt 108: exit(curdb->fn(argc, argv));
1.1 otto 109: break;
110: }
111: }
1.2 deraadt 112: fprintf(stderr, "%s: unknown database: %s\n", __progname, argv[1]);
1.1 otto 113: return RV_USAGE;
114: }
115:
116: static int
117: usage(void)
118: {
1.2 deraadt 119: fprintf(stderr, "usage: %s database [key ...]\n", __progname);
1.1 otto 120: exit(RV_USAGE);
121: /* NOTREACHED */
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
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);
1.2 deraadt 140: va_end(ap);
1.1 otto 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:
1.2 deraadt 150: #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp)
1.1 otto 151:
152: static int
153: ethers(int argc, char *argv[])
154: {
1.9 deraadt 155: char hostname[HOST_NAME_MAX+1], *hp;
1.2 deraadt 156: int i, rv = RV_OK;
1.1 otto 157: struct ether_addr ea, *eap;
158:
159: if (argc == 2) {
1.2 deraadt 160: fprintf(stderr, "%s: Enumeration not supported on ethers\n",
161: __progname);
1.1 otto 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:
1.2 deraadt 185: #define GROUPPRINT \
186: printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
187: gr->gr_name, gr->gr_passwd, gr->gr_gid)
1.1 otto 188:
189: static int
190: group(int argc, char *argv[])
191: {
1.2 deraadt 192: int i, rv = RV_OK;
1.1 otto 193: struct group *gr;
194:
195: setgroupent(1);
196: if (argc == 2) {
197: while ((gr = getgrent()) != NULL)
198: GROUPPRINT;
199: } else {
200: for (i = 2; i < argc; i++) {
1.2 deraadt 201: const char *err;
202: long long id = strtonum(argv[i], 0, UINT_MAX, &err);
203:
204: if (!err)
1.1 otto 205: gr = getgrgid((gid_t)id);
206: else
207: gr = getgrnam(argv[i]);
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
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, " ", " ", "%-16s %s", buf, he->h_name);
228: }
1.6 florian 229: static int
230: hostsaddrinfo(char* name)
231: {
232: struct addrinfo hints, *res, *res0;
233: void *src;
234: int rv;
235: char buf[INET6_ADDRSTRLEN];
236:
237: rv = RV_NOTFOUND;
238: memset(buf, 0, sizeof(buf));
239: memset(&hints, 0, sizeof(hints));
240: hints.ai_family = PF_UNSPEC;
241: hints.ai_socktype = SOCK_DGRAM;
242:
243: if (getaddrinfo(name, NULL, &hints, &res0) == 0) {
244: for (res = res0; res; res = res->ai_next) {
245: switch (res->ai_family) {
246: case AF_INET:
247: src = &((struct sockaddr_in*)
248: res->ai_addr)->sin_addr;
249: break;
250: case AF_INET6:
251: src = &((struct sockaddr_in6*)
252: res->ai_addr)->sin6_addr;
253: break;
254: default: /* not reached */
255: src = NULL;
256: }
257: if (src==NULL || inet_ntop(res->ai_family, src, buf,
258: sizeof(buf)) == NULL)
259: strlcpy(buf, "# unknown", sizeof(buf));
260: else
261: rv = RV_OK;
262: printf("%-39s %s\n", buf, name);
263: }
264: freeaddrinfo(res0);
265: }
266:
267: return (rv);
268: }
1.1 otto 269:
270: static int
271: hosts(int argc, char *argv[])
272: {
1.2 deraadt 273: char addr[IN6ADDRSZ];
274: int i, rv = RV_OK;
1.1 otto 275: struct hostent *he;
276:
277: if (argc == 2) {
1.7 schwarze 278: fprintf(stderr, "%s: Enumeration not supported on hosts\n",
279: __progname);
280: rv = RV_NOENUM;
1.1 otto 281: } else {
282: for (i = 2; i < argc; i++) {
1.6 florian 283: he = NULL;
1.1 otto 284: if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
285: he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
286: else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
287: he = gethostbyaddr(addr, INADDRSZ, AF_INET);
288: if (he != NULL)
289: hostsprint(he);
1.6 florian 290: else if ((rv = hostsaddrinfo(argv[i])) == RV_NOTFOUND)
1.1 otto 291: break;
292: }
293: }
294: return rv;
295: }
296:
1.2 deraadt 297: #define PASSWDPRINT \
298: printf("%s:%s:%u:%u:%s:%s:%s\n", \
299: pw->pw_name, pw->pw_passwd, pw->pw_uid, \
300: pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
1.1 otto 301:
302: static int
303: passwd(int argc, char *argv[])
304: {
1.2 deraadt 305: int i, rv = RV_OK;
1.1 otto 306: struct passwd *pw;
307:
308: setpassent(1);
309: if (argc == 2) {
310: while ((pw = getpwent()) != NULL)
311: PASSWDPRINT;
312: } else {
313: for (i = 2; i < argc; i++) {
1.2 deraadt 314: const char *err;
315: long long id = strtonum(argv[i], 0, UINT_MAX, &err);
316:
317: if (!err)
1.1 otto 318: pw = getpwuid((uid_t)id);
319: else
320: pw = getpwnam(argv[i]);
321: if (pw != NULL)
322: PASSWDPRINT;
323: else {
324: rv = RV_NOTFOUND;
325: break;
326: }
327: }
328: }
329: endpwent();
330: return rv;
331: }
332:
1.2 deraadt 333: #define PROTOCOLSPRINT \
334: printfmtstrings(pe->p_aliases, " ", " ", \
335: "%-16s %5d", pe->p_name, pe->p_proto)
1.1 otto 336:
337: static int
338: protocols(int argc, char *argv[])
339: {
340: struct protoent *pe;
1.2 deraadt 341: int i, rv = RV_OK;
1.1 otto 342:
343: setprotoent(1);
344: if (argc == 2) {
345: while ((pe = getprotoent()) != NULL)
346: PROTOCOLSPRINT;
347: } else {
348: for (i = 2; i < argc; i++) {
1.2 deraadt 349: const char *err;
350: long long id = strtonum(argv[i], 0, UINT_MAX, &err);
351:
352: if (!err)
1.1 otto 353: pe = getprotobynumber((int)id);
354: else
355: pe = getprotobyname(argv[i]);
356: if (pe != NULL)
357: PROTOCOLSPRINT;
358: else {
359: rv = RV_NOTFOUND;
360: break;
361: }
362: }
363: }
364: endprotoent();
365: return rv;
366: }
367:
1.2 deraadt 368: #define RPCPRINT \
369: printfmtstrings(re->r_aliases, " ", " ", \
370: "%-16s %6d", re->r_name, re->r_number)
1.1 otto 371:
372: static int
373: rpc(int argc, char *argv[])
374: {
375: struct rpcent *re;
1.2 deraadt 376: int i, rv = RV_OK;
1.1 otto 377:
378: setrpcent(1);
379: if (argc == 2) {
380: while ((re = getrpcent()) != NULL)
381: RPCPRINT;
382: } else {
383: for (i = 2; i < argc; i++) {
1.2 deraadt 384: const char *err;
385: long long id = strtonum(argv[i], 0, UINT_MAX, &err);
386:
387: if (!err)
1.1 otto 388: re = getrpcbynumber((int)id);
389: else
390: re = getrpcbyname(argv[i]);
391: if (re != NULL)
392: RPCPRINT;
393: else {
394: rv = RV_NOTFOUND;
395: break;
396: }
397: }
398: }
399: endrpcent();
400: return rv;
401: }
402:
1.2 deraadt 403: #define SERVICESPRINT \
404: printfmtstrings(se->s_aliases, " ", " ", \
405: "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto)
1.1 otto 406:
407: static int
408: services(int argc, char *argv[])
409: {
410: struct servent *se;
1.2 deraadt 411: int i, rv = RV_OK;
1.1 otto 412:
413: setservent(1);
414: if (argc == 2) {
415: while ((se = getservent()) != NULL)
416: SERVICESPRINT;
417: } else {
418: for (i = 2; i < argc; i++) {
1.2 deraadt 419: const char *err;
420: long long id;
421: char *proto = strchr(argv[i], '/');
422:
1.1 otto 423: if (proto != NULL)
424: *proto++ = '\0';
1.2 deraadt 425: id = strtonum(argv[i], 0, UINT_MAX, &err);
426: if (!err)
1.4 otto 427: se = getservbyport(htons((u_short)id), proto);
1.1 otto 428: else
429: se = getservbyname(argv[i], proto);
430: if (se != NULL)
431: SERVICESPRINT;
432: else {
433: rv = RV_NOTFOUND;
434: break;
435: }
436: }
437: }
438: endservent();
439: return rv;
440: }
441:
1.2 deraadt 442: #define SHELLSPRINT printf("%s\n", sh)
1.1 otto 443:
444: static int
445: shells(int argc, char *argv[])
446: {
447: const char *sh;
1.2 deraadt 448: int i, rv = RV_OK;
1.1 otto 449:
450: setusershell();
451: if (argc == 2) {
452: while ((sh = getusershell()) != NULL)
453: SHELLSPRINT;
454: } else {
455: for (i = 2; i < argc; i++) {
456: setusershell();
457: while ((sh = getusershell()) != NULL) {
458: if (strcmp(sh, argv[i]) == 0) {
459: SHELLSPRINT;
460: break;
461: }
462: }
463: if (sh == NULL) {
464: rv = RV_NOTFOUND;
465: break;
466: }
467: }
468: }
469: endusershell();
470: return rv;
471: }