/*- * Copyright (c) 2004-2006 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Luke Mewburn. * Timo Teräs cleaned up the code for use in Alpine Linux with musl libc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include enum { RV_OK = 0, RV_USAGE = 1, RV_NOTFOUND = 2, RV_NOENUM = 3 }; static int usage(const char *); static int parsenum(const char *word, unsigned long *result) { unsigned long num; char *ep; if (!isdigit((unsigned char)word[0])) return 0; errno = 0; num = strtoul(word, &ep, 10); if (num == ULONG_MAX && errno == ERANGE) return 0; if (*ep != '\0') return 0; *result = num; return 1; } /* * printfmtstrings -- * vprintf(format, ...), * then the aliases (beginning with prefix, separated by sep), * then a newline */ __attribute__ ((format (printf, 4, 5))) static void printfmtstrings(char *strings[], const char *prefix, const char *sep, const char *fmt, ...) { va_list ap; const char *curpref; size_t i; va_start(ap, fmt); (void)vprintf(fmt, ap); va_end(ap); curpref = prefix; for (i = 0; strings[i] != NULL; i++) { (void)printf("%s%s", curpref, strings[i]); curpref = sep; } (void)printf("\n"); } static int ethers(int argc, char *argv[]) { char hostname[MAXHOSTNAMELEN + 1], *hp; struct ether_addr ea, *eap; int i, rv; if (argc == 2) { warnx("Enumeration not supported on ethers"); return RV_NOENUM; } rv = RV_OK; for (i = 2; i < argc; i++) { if ((eap = ether_aton(argv[i])) == NULL) { eap = &ea; hp = argv[i]; if (ether_hostton(hp, eap) != 0) { rv = RV_NOTFOUND; break; } } else { hp = hostname; if (ether_ntohost(hp, eap) != 0) { rv = RV_NOTFOUND; break; } } (void)printf("%-17s %s\n", ether_ntoa(eap), hp); } return rv; } static void groupprint(const struct group *gr) { printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", gr->gr_name, gr->gr_passwd, gr->gr_gid); } static int group(int argc, char *argv[]) { struct group *gr; unsigned long id; int i, rv; rv = RV_OK; if (argc == 2) { while ((gr = getgrent()) != NULL) groupprint(gr); } else { for (i = 2; i < argc; i++) { if (parsenum(argv[i], &id)) gr = getgrgid((gid_t)id); else gr = getgrnam(argv[i]); if (gr == NULL) { rv = RV_NOTFOUND; break; } groupprint(gr); } } endgrent(); return rv; } static void hostsprint(const struct hostent *he) { char buf[INET6_ADDRSTRLEN]; if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL) (void)strlcpy(buf, "# unknown", sizeof(buf)); printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name); } static int hosts(int argc, char *argv[]) { struct hostent *he; char addr[IN6ADDRSZ]; int i, rv; sethostent(1); rv = RV_OK; if (argc == 2) { while ((he = gethostent()) != NULL) hostsprint(he); } else { for (i = 2; i < argc; i++) { if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6); else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0) he = gethostbyaddr(addr, INADDRSZ, AF_INET); else if ((he = gethostbyname2(argv[i], AF_INET6)) == NULL) he = gethostbyname2(argv[i], AF_INET); if (he == NULL) { rv = RV_NOTFOUND; break; } hostsprint(he); } } endhostent(); return rv; } static int ahosts_ex(int family, int flags, int argc, char *argv[]) { static const char *socktypes[] = { [SOCK_STREAM] = "STREAM", [SOCK_DGRAM] = "DGRAM", [SOCK_RAW] = "RAW", [SOCK_RDM] = "RDM", [SOCK_SEQPACKET] = "SEQPACKET", [SOCK_DCCP] = "DCCP", [SOCK_PACKET] = "PACKET", }; const char *sockstr; char sockbuf[16], buf[INET6_ADDRSTRLEN]; struct addrinfo *res, *r, hint; void *addr; int i; if (argc == 2) return hosts(argc, argv); hint = (struct addrinfo) { .ai_family = family, .ai_flags = AI_ADDRCONFIG | AI_CANONNAME | flags, }; for (i = 2; i < argc; i++) { if (getaddrinfo(argv[i], 0, &hint, &res) != 0) return RV_NOTFOUND; for (r = res; r; r = r->ai_next) { sockstr = NULL; if (r->ai_socktype >= 0 && r->ai_socktype < sizeof(socktypes)/sizeof(socktypes[0])) sockstr = socktypes[r->ai_socktype]; if (!sockstr) { sprintf(buf, "%d", r->ai_socktype); sockstr = sockbuf; } switch (r->ai_family) { case AF_INET: addr = &((struct sockaddr_in*) r->ai_addr)->sin_addr; break; case AF_INET6: addr = &((struct sockaddr_in6*) r->ai_addr)->sin6_addr; break; default: continue; } if (inet_ntop(r->ai_family, addr, buf, sizeof(buf)) == NULL) (void)strlcpy(buf, "# unknown", sizeof(buf)); printf("%-15s %-6s %s\n", buf, sockstr, r->ai_canonname ?: ""); } } return RV_OK; } static int ahosts(int argc, char *argv[]) { return ahosts_ex(AF_UNSPEC, 0, argc, argv); } static int ahostsv4(int argc, char *argv[]) { return ahosts_ex(AF_INET, 0, argc, argv); } static int ahostsv6(int argc, char *argv[]) { return ahosts_ex(AF_INET6, AI_V4MAPPED, argc, argv); } static void networksprint(const struct netent *ne) { char buf[INET6_ADDRSTRLEN]; struct in_addr ianet; ianet = inet_makeaddr(ne->n_net, 0); if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL) (void)strlcpy(buf, "# unknown", sizeof(buf)); printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf); } static int networks(int argc, char *argv[]) { struct netent *ne; in_addr_t net; int i, rv; setnetent(1); rv = RV_OK; if (argc == 2) { while ((ne = getnetent()) != NULL) networksprint(ne); } else { for (i = 2; i < argc; i++) { net = inet_network(argv[i]); if (net != INADDR_NONE) ne = getnetbyaddr(net, AF_INET); else ne = getnetbyname(argv[i]); if (ne != NULL) { rv = RV_NOTFOUND; break; } networksprint(ne); } } endnetent(); return rv; } static void passwdprint(struct passwd *pw) { (void)printf("%s:%s:%u:%u:%s:%s:%s\n", pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell); } static int passwd(int argc, char *argv[]) { struct passwd *pw; unsigned long id; int i, rv; rv = RV_OK; if (argc == 2) { while ((pw = getpwent()) != NULL) passwdprint(pw); } else { for (i = 2; i < argc; i++) { if (parsenum(argv[i], &id)) pw = getpwuid((uid_t)id); else pw = getpwnam(argv[i]); if (pw == NULL) { rv = RV_NOTFOUND; break; } passwdprint(pw); } } endpwent(); return rv; } static void protocolsprint(struct protoent *pe) { printfmtstrings(pe->p_aliases, " ", " ", "%-16s %5d", pe->p_name, pe->p_proto); } static int protocols(int argc, char *argv[]) { struct protoent *pe; unsigned long id; int i, rv; setprotoent(1); rv = RV_OK; if (argc == 2) { while ((pe = getprotoent()) != NULL) protocolsprint(pe); } else { for (i = 2; i < argc; i++) { if (parsenum(argv[i], &id)) pe = getprotobynumber((int)id); else pe = getprotobyname(argv[i]); if (pe == NULL) { rv = RV_NOTFOUND; break; } protocolsprint(pe); } } endprotoent(); return rv; } static void servicesprint(struct servent *se) { printfmtstrings(se->s_aliases, " ", " ", "%-16s %5d/%s", se->s_name, ntohs(se->s_port), se->s_proto); } static int services(int argc, char *argv[]) { struct servent *se; unsigned long id; char *proto; int i, rv; setservent(1); rv = RV_OK; if (argc == 2) { while ((se = getservent()) != NULL) servicesprint(se); } else { for (i = 2; i < argc; i++) { proto = strchr(argv[i], '/'); if (proto != NULL) *proto++ = '\0'; if (parsenum(argv[i], &id)) se = getservbyport(htons(id), proto); else se = getservbyname(argv[i], proto); if (se == NULL) { rv = RV_NOTFOUND; break; } servicesprint(se); } } endservent(); return rv; } static int shadow(int argc, char *argv[]) { struct spwd *sp; int i, rv; rv = RV_OK; if (argc == 2) { while ((sp = getspent()) != NULL) putspent(sp, stdout); } else { for (i = 2; i < argc; i++) { sp = getspnam(argv[i]); if (sp == NULL) { rv = RV_NOTFOUND; break; } putspent(sp, stdout); } } endspent(); return rv; } static int shells(int argc, char *argv[]) { const char *sh; int i, rv; setusershell(); rv = RV_OK; if (argc == 2) { while ((sh = getusershell()) != NULL) (void)printf("%s\n", sh); } else { for (i = 2; i < argc; i++) { setusershell(); while ((sh = getusershell()) != NULL) { if (strcmp(sh, argv[i]) == 0) { (void)printf("%s\n", sh); break; } } if (sh == NULL) { rv = RV_NOTFOUND; break; } } } endusershell(); return rv; } static struct getentdb { const char *name; int (*callback)(int, char *[]); } databases[] = { { "ethers", ethers, }, { "group", group, }, { "hosts", hosts, }, { "ahosts", ahosts, }, { "ahostsv4", ahostsv4, }, { "ahostsv6", ahostsv6, }, { "networks", networks, }, { "passwd", passwd, }, { "protocols", protocols, }, { "services", services, }, { "shadow", shadow, }, { "shells", shells, }, { NULL, NULL, }, }; static int usage(const char *arg0) { struct getentdb *curdb; size_t i; (void)fprintf(stderr, "Usage: %s database [key ...]\n", arg0); (void)fprintf(stderr, "\tdatabase may be one of:"); for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) { if (i % 7 == 0) (void)fputs("\n\t\t", stderr); (void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ", curdb->name); } (void)fprintf(stderr, "\n"); exit(RV_USAGE); /* NOTREACHED */ } int main(int argc, char *argv[]) { struct getentdb *curdb; if (argc < 2) usage(argv[0]); for (curdb = databases; curdb->name != NULL; curdb++) if (strcmp(curdb->name, argv[1]) == 0) return (*curdb->callback)(argc, argv); warn("Unknown database `%s'", argv[1]); usage(argv[0]); /* NOTREACHED */ }