projects/aports·blob master · refs

536 lines · 11.4 KiB

1/*-
2 * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Luke Mewburn.
7 * Timo Teräs cleaned up the code for use in Alpine Linux with musl libc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/socket.h>
32#include <sys/param.h>
33#include <ctype.h>
34#include <errno.h>
35#include <limits.h>
36#include <netdb.h>
37#include <pwd.h>
38#include <grp.h>
39#include <shadow.h>
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdbool.h>
43#include <stdlib.h>
44#include <string.h>
45#include <unistd.h>
46#include <paths.h>
47#include <err.h>
48
49#include <arpa/inet.h>
50#include <arpa/nameser.h>
51
52#include <net/if.h>
53#include <net/ethernet.h>
54#include <netinet/ether.h>
55#include <netinet/in.h>
56
57enum {
58 RV_OK = 0,
59 RV_USAGE = 1,
60 RV_NOTFOUND = 2,
61 RV_NOENUM = 3
62};
63
64static int usage(const char *);
65
66static int parsenum(const char *word, unsigned long *result)
67{
68 unsigned long num;
69 char *ep;
70
71 if (!isdigit((unsigned char)word[0]))
72 return 0;
73 errno = 0;
74 num = strtoul(word, &ep, 10);
75 if (num == ULONG_MAX && errno == ERANGE)
76 return 0;
77 if (*ep != '\0')
78 return 0;
79 *result = num;
80 return 1;
81}
82
83/*
84 * printfmtstrings --
85 * vprintf(format, ...),
86 * then the aliases (beginning with prefix, separated by sep),
87 * then a newline
88 */
89__attribute__ ((format (printf, 4, 5)))
90static void printfmtstrings(char *strings[], const char *prefix, const char *sep,
91 const char *fmt, ...)
92{
93 va_list ap;
94 const char *curpref;
95 size_t i;
96
97 va_start(ap, fmt);
98 (void)vprintf(fmt, ap);
99 va_end(ap);
100
101 curpref = prefix;
102 for (i = 0; strings[i] != NULL; i++) {
103 (void)printf("%s%s", curpref, strings[i]);
104 curpref = sep;
105 }
106 (void)printf("\n");
107}
108
109static int ethers(int argc, char *argv[])
110{
111 char hostname[MAXHOSTNAMELEN + 1], *hp;
112 struct ether_addr ea, *eap;
113 int i, rv;
114
115 if (argc == 2) {
116 warnx("Enumeration not supported on ethers");
117 return RV_NOENUM;
118 }
119
120 rv = RV_OK;
121 for (i = 2; i < argc; i++) {
122 if ((eap = ether_aton(argv[i])) == NULL) {
123 eap = &ea;
124 hp = argv[i];
125 if (ether_hostton(hp, eap) != 0) {
126 rv = RV_NOTFOUND;
127 break;
128 }
129 } else {
130 hp = hostname;
131 if (ether_ntohost(hp, eap) != 0) {
132 rv = RV_NOTFOUND;
133 break;
134 }
135 }
136 (void)printf("%-17s %s\n", ether_ntoa(eap), hp);
137 }
138 return rv;
139}
140
141static void groupprint(const struct group *gr)
142{
143 printfmtstrings(gr->gr_mem, "", ",", "%s:%s:%u:",
144 gr->gr_name, gr->gr_passwd, gr->gr_gid);
145}
146
147static int group(int argc, char *argv[])
148{
149 struct group *gr;
150 unsigned long id;
151 int i, rv;
152
153 rv = RV_OK;
154 if (argc == 2) {
155 while ((gr = getgrent()) != NULL)
156 groupprint(gr);
157 } else {
158 for (i = 2; i < argc; i++) {
159 if (parsenum(argv[i], &id))
160 gr = getgrgid((gid_t)id);
161 else
162 gr = getgrnam(argv[i]);
163 if (gr == NULL) {
164 rv = RV_NOTFOUND;
165 break;
166 }
167 groupprint(gr);
168 }
169 }
170 endgrent();
171 return rv;
172}
173
174static void hostsprint(const struct hostent *he)
175{
176 char buf[INET6_ADDRSTRLEN];
177
178 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
179 (void)strlcpy(buf, "# unknown", sizeof(buf));
180 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
181}
182
183static int hosts(int argc, char *argv[])
184{
185 struct hostent *he;
186 char addr[IN6ADDRSZ];
187 int i, rv;
188
189 sethostent(1);
190 rv = RV_OK;
191 if (argc == 2) {
192 while ((he = gethostent()) != NULL)
193 hostsprint(he);
194 } else {
195 for (i = 2; i < argc; i++) {
196 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
197 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
198 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
199 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
200 else if ((he = gethostbyname2(argv[i], AF_INET6)) == NULL)
201 he = gethostbyname2(argv[i], AF_INET);
202 if (he == NULL) {
203 rv = RV_NOTFOUND;
204 break;
205 }
206 hostsprint(he);
207 }
208 }
209 endhostent();
210 return rv;
211}
212
213static int ahosts_ex(int family, int flags, int argc, char *argv[])
214{
215 static const char *socktypes[] = {
216 [SOCK_STREAM] = "STREAM",
217 [SOCK_DGRAM] = "DGRAM",
218 [SOCK_RAW] = "RAW",
219 [SOCK_RDM] = "RDM",
220 [SOCK_SEQPACKET] = "SEQPACKET",
221 [SOCK_DCCP] = "DCCP",
222 [SOCK_PACKET] = "PACKET",
223 };
224 const char *sockstr;
225 char sockbuf[16], buf[INET6_ADDRSTRLEN];
226 struct addrinfo *res, *r, hint;
227 void *addr;
228 int i;
229
230 if (argc == 2)
231 return hosts(argc, argv);
232
233 hint = (struct addrinfo) {
234 .ai_family = family,
235 .ai_flags = AI_ADDRCONFIG | AI_CANONNAME | flags,
236 };
237
238 for (i = 2; i < argc; i++) {
239 if (getaddrinfo(argv[i], 0, &hint, &res) != 0)
240 return RV_NOTFOUND;
241
242 for (r = res; r; r = r->ai_next) {
243 sockstr = NULL;
244 if (r->ai_socktype >= 0 && r->ai_socktype < sizeof(socktypes)/sizeof(socktypes[0]))
245 sockstr = socktypes[r->ai_socktype];
246 if (!sockstr) {
247 sprintf(buf, "%d", r->ai_socktype);
248 sockstr = sockbuf;
249 }
250 switch (r->ai_family) {
251 case AF_INET:
252 addr = &((struct sockaddr_in*) r->ai_addr)->sin_addr;
253 break;
254 case AF_INET6:
255 addr = &((struct sockaddr_in6*) r->ai_addr)->sin6_addr;
256 break;
257 default:
258 continue;
259 }
260 if (inet_ntop(r->ai_family, addr, buf, sizeof(buf)) == NULL)
261 (void)strlcpy(buf, "# unknown", sizeof(buf));
262 printf("%-15s %-6s %s\n", buf, sockstr, r->ai_canonname ?: "");
263 }
264 }
265
266 return RV_OK;
267}
268
269static int ahosts(int argc, char *argv[])
270{
271 return ahosts_ex(AF_UNSPEC, 0, argc, argv);
272}
273
274static int ahostsv4(int argc, char *argv[])
275{
276 return ahosts_ex(AF_INET, 0, argc, argv);
277}
278
279static int ahostsv6(int argc, char *argv[])
280{
281 return ahosts_ex(AF_INET6, AI_V4MAPPED, argc, argv);
282}
283
284static void networksprint(const struct netent *ne)
285{
286 char buf[INET6_ADDRSTRLEN];
287 struct in_addr ianet;
288
289 ianet = inet_makeaddr(ne->n_net, 0);
290 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
291 (void)strlcpy(buf, "# unknown", sizeof(buf));
292 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
293}
294
295static int networks(int argc, char *argv[])
296{
297 struct netent *ne;
298 in_addr_t net;
299 int i, rv;
300
301 setnetent(1);
302 rv = RV_OK;
303 if (argc == 2) {
304 while ((ne = getnetent()) != NULL)
305 networksprint(ne);
306 } else {
307 for (i = 2; i < argc; i++) {
308 net = inet_network(argv[i]);
309 if (net != INADDR_NONE)
310 ne = getnetbyaddr(net, AF_INET);
311 else
312 ne = getnetbyname(argv[i]);
313 if (ne == NULL) {
314 rv = RV_NOTFOUND;
315 break;
316 }
317 networksprint(ne);
318 }
319 }
320 endnetent();
321 return rv;
322}
323
324static void passwdprint(struct passwd *pw)
325{
326 (void)printf("%s:%s:%u:%u:%s:%s:%s\n",
327 pw->pw_name, pw->pw_passwd, pw->pw_uid,
328 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell);
329}
330
331static int passwd(int argc, char *argv[])
332{
333 struct passwd *pw;
334 unsigned long id;
335 int i, rv;
336
337 rv = RV_OK;
338 if (argc == 2) {
339 while ((pw = getpwent()) != NULL)
340 passwdprint(pw);
341 } else {
342 for (i = 2; i < argc; i++) {
343 if (parsenum(argv[i], &id))
344 pw = getpwuid((uid_t)id);
345 else
346 pw = getpwnam(argv[i]);
347 if (pw == NULL) {
348 rv = RV_NOTFOUND;
349 break;
350 }
351 passwdprint(pw);
352 }
353 }
354 endpwent();
355 return rv;
356}
357
358static void protocolsprint(struct protoent *pe)
359{
360 printfmtstrings(pe->p_aliases, " ", " ",
361 "%-16s %5d", pe->p_name, pe->p_proto);
362}
363
364static int protocols(int argc, char *argv[])
365{
366 struct protoent *pe;
367 unsigned long id;
368 int i, rv;
369
370 setprotoent(1);
371 rv = RV_OK;
372 if (argc == 2) {
373 while ((pe = getprotoent()) != NULL)
374 protocolsprint(pe);
375 } else {
376 for (i = 2; i < argc; i++) {
377 if (parsenum(argv[i], &id))
378 pe = getprotobynumber((int)id);
379 else
380 pe = getprotobyname(argv[i]);
381 if (pe == NULL) {
382 rv = RV_NOTFOUND;
383 break;
384 }
385 protocolsprint(pe);
386 }
387 }
388 endprotoent();
389 return rv;
390}
391
392static void servicesprint(struct servent *se)
393{
394 printfmtstrings(se->s_aliases, " ", " ",
395 "%-16s %5d/%s",
396 se->s_name, ntohs(se->s_port), se->s_proto);
397
398}
399
400static int services(int argc, char *argv[])
401{
402 struct servent *se;
403 unsigned long id;
404 char *proto;
405 int i, rv;
406
407 setservent(1);
408 rv = RV_OK;
409 if (argc == 2) {
410 while ((se = getservent()) != NULL)
411 servicesprint(se);
412 } else {
413 for (i = 2; i < argc; i++) {
414 proto = strchr(argv[i], '/');
415 if (proto != NULL)
416 *proto++ = '\0';
417 if (parsenum(argv[i], &id))
418 se = getservbyport(htons(id), proto);
419 else
420 se = getservbyname(argv[i], proto);
421 if (se == NULL) {
422 rv = RV_NOTFOUND;
423 break;
424 }
425 servicesprint(se);
426 }
427 }
428 endservent();
429 return rv;
430}
431
432static int shadow(int argc, char *argv[])
433{
434 struct spwd *sp;
435 int i, rv;
436
437 rv = RV_OK;
438 if (argc == 2) {
439 while ((sp = getspent()) != NULL)
440 putspent(sp, stdout);
441 } else {
442 for (i = 2; i < argc; i++) {
443 sp = getspnam(argv[i]);
444 if (sp == NULL) {
445 rv = RV_NOTFOUND;
446 break;
447 }
448 putspent(sp, stdout);
449 }
450 }
451 endspent();
452 return rv;
453}
454
455static int shells(int argc, char *argv[])
456{
457 const char *sh;
458 int i, rv;
459
460 setusershell();
461 rv = RV_OK;
462 if (argc == 2) {
463 while ((sh = getusershell()) != NULL)
464 (void)printf("%s\n", sh);
465 } else {
466 for (i = 2; i < argc; i++) {
467 setusershell();
468 while ((sh = getusershell()) != NULL) {
469 if (strcmp(sh, argv[i]) == 0) {
470 (void)printf("%s\n", sh);
471 break;
472 }
473 }
474 if (sh == NULL) {
475 rv = RV_NOTFOUND;
476 break;
477 }
478 }
479 }
480 endusershell();
481 return rv;
482}
483
484static struct getentdb {
485 const char *name;
486 int (*callback)(int, char *[]);
487} databases[] = {
488 { "ethers", ethers, },
489 { "group", group, },
490 { "hosts", hosts, },
491 { "ahosts", ahosts, },
492 { "ahostsv4", ahostsv4, },
493 { "ahostsv6", ahostsv6, },
494 { "networks", networks, },
495 { "passwd", passwd, },
496 { "protocols", protocols, },
497 { "services", services, },
498 { "shadow", shadow, },
499 { "shells", shells, },
500
501 { NULL, NULL, },
502};
503
504static int usage(const char *arg0)
505{
506 struct getentdb *curdb;
507 size_t i;
508
509 (void)fprintf(stderr, "Usage: %s database [key ...]\n", arg0);
510 (void)fprintf(stderr, "\tdatabase may be one of:");
511 for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) {
512 if (i % 7 == 0)
513 (void)fputs("\n\t\t", stderr);
514 (void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ",
515 curdb->name);
516 }
517 (void)fprintf(stderr, "\n");
518 exit(RV_USAGE);
519 /* NOTREACHED */
520}
521
522int
523main(int argc, char *argv[])
524{
525 struct getentdb *curdb;
526
527 if (argc < 2)
528 usage(argv[0]);
529 for (curdb = databases; curdb->name != NULL; curdb++)
530 if (strcmp(curdb->name, argv[1]) == 0)
531 return (*curdb->callback)(argc, argv);
532
533 warn("Unknown database `%s'", argv[1]);
534 usage(argv[0]);
535 /* NOTREACHED */
536}