getent.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  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. #include <sys/socket.h>
  31. #include <sys/param.h>
  32. #include <ctype.h>
  33. #include <errno.h>
  34. #include <limits.h>
  35. #include <netdb.h>
  36. #include <pwd.h>
  37. #include <grp.h>
  38. #include <stdio.h>
  39. #include <stdarg.h>
  40. #include <stdbool.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <unistd.h>
  44. #include <paths.h>
  45. #include <err.h>
  46. #include <arpa/inet.h>
  47. #include <arpa/nameser.h>
  48. #include <net/if.h>
  49. #include <net/ethernet.h>
  50. #include <netinet/ether.h>
  51. #include <netinet/in.h>
  52. enum {
  53. RV_OK = 0,
  54. RV_USAGE = 1,
  55. RV_NOTFOUND = 2,
  56. RV_NOENUM = 3
  57. };
  58. static int usage(const char *);
  59. static int parsenum(const char *word, unsigned long *result)
  60. {
  61. unsigned long num;
  62. char *ep;
  63. if (!isdigit((unsigned char)word[0]))
  64. return 0;
  65. errno = 0;
  66. num = strtoul(word, &ep, 10);
  67. if (num == ULONG_MAX && errno == ERANGE)
  68. return 0;
  69. if (*ep != '\0')
  70. return 0;
  71. *result = num;
  72. return 1;
  73. }
  74. /*
  75. * printfmtstrings --
  76. * vprintf(format, ...),
  77. * then the aliases (beginning with prefix, separated by sep),
  78. * then a newline
  79. */
  80. __attribute__ ((format (printf, 4, 5)))
  81. static void printfmtstrings(char *strings[], const char *prefix, const char *sep,
  82. const char *fmt, ...)
  83. {
  84. va_list ap;
  85. const char *curpref;
  86. size_t i;
  87. va_start(ap, fmt);
  88. (void)vprintf(fmt, ap);
  89. va_end(ap);
  90. curpref = prefix;
  91. for (i = 0; strings[i] != NULL; i++) {
  92. (void)printf("%s%s", curpref, strings[i]);
  93. curpref = sep;
  94. }
  95. (void)printf("\n");
  96. }
  97. static int ethers(int argc, char *argv[])
  98. {
  99. char hostname[MAXHOSTNAMELEN + 1], *hp;
  100. struct ether_addr ea, *eap;
  101. int i, rv;
  102. if (argc == 2) {
  103. warnx("Enumeration not supported on ethers");
  104. return RV_NOENUM;
  105. }
  106. rv = RV_OK;
  107. for (i = 2; i < argc; i++) {
  108. if ((eap = ether_aton(argv[i])) == NULL) {
  109. eap = &ea;
  110. hp = argv[i];
  111. if (ether_hostton(hp, eap) != 0) {
  112. rv = RV_NOTFOUND;
  113. break;
  114. }
  115. } else {
  116. hp = hostname;
  117. if (ether_ntohost(hp, eap) != 0) {
  118. rv = RV_NOTFOUND;
  119. break;
  120. }
  121. }
  122. (void)printf("%-17s %s\n", ether_ntoa(eap), hp);
  123. }
  124. return rv;
  125. }
  126. static void groupprint(const struct group *gr)
  127. {
  128. printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u",
  129. gr->gr_name, gr->gr_passwd, gr->gr_gid);
  130. }
  131. static int group(int argc, char *argv[])
  132. {
  133. struct group *gr;
  134. unsigned long id;
  135. int i, rv;
  136. rv = RV_OK;
  137. if (argc == 2) {
  138. while ((gr = getgrent()) != NULL)
  139. groupprint(gr);
  140. } else {
  141. for (i = 2; i < argc; i++) {
  142. if (parsenum(argv[i], &id))
  143. gr = getgrgid((gid_t)id);
  144. else
  145. gr = getgrnam(argv[i]);
  146. if (gr == NULL) {
  147. rv = RV_NOTFOUND;
  148. break;
  149. }
  150. groupprint(gr);
  151. }
  152. }
  153. endgrent();
  154. return rv;
  155. }
  156. static void hostsprint(const struct hostent *he)
  157. {
  158. char buf[INET6_ADDRSTRLEN];
  159. if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
  160. (void)strlcpy(buf, "# unknown", sizeof(buf));
  161. printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
  162. }
  163. static int hosts(int argc, char *argv[])
  164. {
  165. struct hostent *he;
  166. char addr[IN6ADDRSZ];
  167. int i, rv;
  168. sethostent(1);
  169. rv = RV_OK;
  170. if (argc == 2) {
  171. while ((he = gethostent()) != NULL)
  172. hostsprint(he);
  173. } else {
  174. for (i = 2; i < argc; i++) {
  175. if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
  176. he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
  177. else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
  178. he = gethostbyaddr(addr, INADDRSZ, AF_INET);
  179. else if ((he = gethostbyname2(argv[i], AF_INET6)) == NULL)
  180. he = gethostbyname2(argv[i], AF_INET);
  181. if (he == NULL) {
  182. rv = RV_NOTFOUND;
  183. break;
  184. }
  185. hostsprint(he);
  186. }
  187. }
  188. endhostent();
  189. return rv;
  190. }
  191. static int ahosts_ex(int family, int flags, int argc, char *argv[])
  192. {
  193. static const char *socktypes[] = {
  194. [SOCK_STREAM] = "STREAM",
  195. [SOCK_DGRAM] = "DGRAM",
  196. [SOCK_RAW] = "RAW",
  197. [SOCK_RDM] = "RDM",
  198. [SOCK_SEQPACKET] = "SEQPACKET",
  199. [SOCK_DCCP] = "DCCP",
  200. [SOCK_PACKET] = "PACKET",
  201. };
  202. const char *sockstr;
  203. char sockbuf[16], buf[INET6_ADDRSTRLEN];
  204. struct addrinfo *res, *r, hint;
  205. void *addr;
  206. int i;
  207. if (argc == 2)
  208. return hosts(argc, argv);
  209. hint = (struct addrinfo) {
  210. .ai_family = family,
  211. .ai_flags = AI_ADDRCONFIG | AI_CANONNAME | flags,
  212. };
  213. for (i = 2; i < argc; i++) {
  214. if (getaddrinfo(argv[i], 0, &hint, &res) != 0)
  215. return RV_NOTFOUND;
  216. for (r = res; r; r = r->ai_next) {
  217. sockstr = NULL;
  218. if (r->ai_socktype >= 0 && r->ai_socktype < sizeof(socktypes)/sizeof(socktypes[0]))
  219. sockstr = socktypes[r->ai_socktype];
  220. if (!sockstr) {
  221. sprintf(buf, "%d", r->ai_socktype);
  222. sockstr = sockbuf;
  223. }
  224. switch (r->ai_family) {
  225. case AF_INET:
  226. addr = &((struct sockaddr_in*) r->ai_addr)->sin_addr;
  227. break;
  228. case AF_INET6:
  229. addr = &((struct sockaddr_in6*) r->ai_addr)->sin6_addr;
  230. break;
  231. default:
  232. continue;
  233. }
  234. if (inet_ntop(r->ai_family, addr, buf, sizeof(buf)) == NULL)
  235. (void)strlcpy(buf, "# unknown", sizeof(buf));
  236. printf("%-15s %-6s %s\n", buf, sockstr, r->ai_canonname ?: "");
  237. }
  238. }
  239. return RV_OK;
  240. }
  241. static int ahosts(int argc, char *argv[])
  242. {
  243. return ahosts_ex(AF_UNSPEC, 0, argc, argv);
  244. }
  245. static int ahostsv4(int argc, char *argv[])
  246. {
  247. return ahosts_ex(AF_INET, 0, argc, argv);
  248. }
  249. static int ahostsv6(int argc, char *argv[])
  250. {
  251. return ahosts_ex(AF_INET6, AI_V4MAPPED, argc, argv);
  252. }
  253. static void networksprint(const struct netent *ne)
  254. {
  255. char buf[INET6_ADDRSTRLEN];
  256. struct in_addr ianet;
  257. ianet = inet_makeaddr(ne->n_net, 0);
  258. if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
  259. (void)strlcpy(buf, "# unknown", sizeof(buf));
  260. printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
  261. }
  262. static int networks(int argc, char *argv[])
  263. {
  264. struct netent *ne;
  265. in_addr_t net;
  266. int i, rv;
  267. setnetent(1);
  268. rv = RV_OK;
  269. if (argc == 2) {
  270. while ((ne = getnetent()) != NULL)
  271. networksprint(ne);
  272. } else {
  273. for (i = 2; i < argc; i++) {
  274. net = inet_network(argv[i]);
  275. if (net != INADDR_NONE)
  276. ne = getnetbyaddr(net, AF_INET);
  277. else
  278. ne = getnetbyname(argv[i]);
  279. if (ne != NULL) {
  280. rv = RV_NOTFOUND;
  281. break;
  282. }
  283. networksprint(ne);
  284. }
  285. }
  286. endnetent();
  287. return rv;
  288. }
  289. static void passwdprint(struct passwd *pw)
  290. {
  291. (void)printf("%s:%s:%u:%u:%s:%s:%s\n",
  292. pw->pw_name, pw->pw_passwd, pw->pw_uid,
  293. pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell);
  294. }
  295. static int passwd(int argc, char *argv[])
  296. {
  297. struct passwd *pw;
  298. unsigned long id;
  299. int i, rv;
  300. rv = RV_OK;
  301. if (argc == 2) {
  302. while ((pw = getpwent()) != NULL)
  303. passwdprint(pw);
  304. } else {
  305. for (i = 2; i < argc; i++) {
  306. if (parsenum(argv[i], &id))
  307. pw = getpwuid((uid_t)id);
  308. else
  309. pw = getpwnam(argv[i]);
  310. if (pw == NULL) {
  311. rv = RV_NOTFOUND;
  312. break;
  313. }
  314. passwdprint(pw);
  315. }
  316. }
  317. endpwent();
  318. return rv;
  319. }
  320. static void protocolsprint(struct protoent *pe)
  321. {
  322. printfmtstrings(pe->p_aliases, " ", " ",
  323. "%-16s %5d", pe->p_name, pe->p_proto);
  324. }
  325. static int protocols(int argc, char *argv[])
  326. {
  327. struct protoent *pe;
  328. unsigned long id;
  329. int i, rv;
  330. setprotoent(1);
  331. rv = RV_OK;
  332. if (argc == 2) {
  333. while ((pe = getprotoent()) != NULL)
  334. protocolsprint(pe);
  335. } else {
  336. for (i = 2; i < argc; i++) {
  337. if (parsenum(argv[i], &id))
  338. pe = getprotobynumber((int)id);
  339. else
  340. pe = getprotobyname(argv[i]);
  341. if (pe == NULL) {
  342. rv = RV_NOTFOUND;
  343. break;
  344. }
  345. protocolsprint(pe);
  346. }
  347. }
  348. endprotoent();
  349. return rv;
  350. }
  351. static void servicesprint(struct servent *se)
  352. {
  353. printfmtstrings(se->s_aliases, " ", " ",
  354. "%-16s %5d/%s",
  355. se->s_name, ntohs(se->s_port), se->s_proto);
  356. }
  357. static int services(int argc, char *argv[])
  358. {
  359. struct servent *se;
  360. unsigned long id;
  361. char *proto;
  362. int i, rv;
  363. setservent(1);
  364. rv = RV_OK;
  365. if (argc == 2) {
  366. while ((se = getservent()) != NULL)
  367. servicesprint(se);
  368. } else {
  369. for (i = 2; i < argc; i++) {
  370. proto = strchr(argv[i], '/');
  371. if (proto != NULL)
  372. *proto++ = '\0';
  373. if (parsenum(argv[i], &id))
  374. se = getservbyport(htons(id), proto);
  375. else
  376. se = getservbyname(argv[i], proto);
  377. if (se == NULL) {
  378. rv = RV_NOTFOUND;
  379. break;
  380. }
  381. servicesprint(se);
  382. }
  383. }
  384. endservent();
  385. return rv;
  386. }
  387. static int shells(int argc, char *argv[])
  388. {
  389. const char *sh;
  390. int i, rv;
  391. setusershell();
  392. rv = RV_OK;
  393. if (argc == 2) {
  394. while ((sh = getusershell()) != NULL)
  395. (void)printf("%s\n", sh);
  396. } else {
  397. for (i = 2; i < argc; i++) {
  398. setusershell();
  399. while ((sh = getusershell()) != NULL) {
  400. if (strcmp(sh, argv[i]) == 0) {
  401. (void)printf("%s\n", sh);
  402. break;
  403. }
  404. }
  405. if (sh == NULL) {
  406. rv = RV_NOTFOUND;
  407. break;
  408. }
  409. }
  410. }
  411. endusershell();
  412. return rv;
  413. }
  414. static struct getentdb {
  415. const char *name;
  416. int (*callback)(int, char *[]);
  417. } databases[] = {
  418. { "ethers", ethers, },
  419. { "group", group, },
  420. { "hosts", hosts, },
  421. { "ahosts", ahosts, },
  422. { "ahostsv4", ahostsv4, },
  423. { "ahostsv6", ahostsv6, },
  424. { "networks", networks, },
  425. { "passwd", passwd, },
  426. { "protocols", protocols, },
  427. { "services", services, },
  428. { "shells", shells, },
  429. { NULL, NULL, },
  430. };
  431. static int usage(const char *arg0)
  432. {
  433. struct getentdb *curdb;
  434. size_t i;
  435. (void)fprintf(stderr, "Usage: %s database [key ...]\n", arg0);
  436. (void)fprintf(stderr, "\tdatabase may be one of:");
  437. for (i = 0, curdb = databases; curdb->name != NULL; curdb++, i++) {
  438. if (i % 7 == 0)
  439. (void)fputs("\n\t\t", stderr);
  440. (void)fprintf(stderr, "%s%s", i % 7 == 0 ? "" : " ",
  441. curdb->name);
  442. }
  443. (void)fprintf(stderr, "\n");
  444. exit(RV_USAGE);
  445. /* NOTREACHED */
  446. }
  447. int
  448. main(int argc, char *argv[])
  449. {
  450. struct getentdb *curdb;
  451. if (argc < 2)
  452. usage(argv[0]);
  453. for (curdb = databases; curdb->name != NULL; curdb++)
  454. if (strcmp(curdb->name, argv[1]) == 0)
  455. return (*curdb->callback)(argc, argv);
  456. warn("Unknown database `%s'", argv[1]);
  457. usage(argv[0]);
  458. /* NOTREACHED */
  459. }