getent.c revision 1.12 1 /* $NetBSD: getent.c,v 1.12 2008/02/04 15:30:45 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2004-2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Luke Mewburn.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 __RCSID("$NetBSD: getent.c,v 1.12 2008/02/04 15:30:45 christos Exp $");
42 #endif /* not lint */
43
44 #include <sys/socket.h>
45
46 #include <assert.h>
47 #include <ctype.h>
48 #include <errno.h>
49 #include <grp.h>
50 #include <limits.h>
51 #include <netdb.h>
52 #include <pwd.h>
53 #include <stdio.h>
54 #include <stdarg.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <paths.h>
59 #include <err.h>
60
61 #include <arpa/inet.h>
62 #include <arpa/nameser.h>
63
64 #include <net/if.h>
65 #include <net/if_ether.h>
66
67 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */
68
69 #include <rpc/rpcent.h>
70
71 #include <disktab.h>
72
73 static int usage(void) __attribute__((__noreturn__));
74 static int parsenum(const char *, unsigned long *);
75 static int disktab(int, char *[]);
76 static int gettytab(int, char *[]);
77 static int ethers(int, char *[]);
78 static int group(int, char *[]);
79 static int hosts(int, char *[]);
80 static int networks(int, char *[]);
81 static int passwd(int, char *[]);
82 static int printcap(int, char *[]);
83 static int protocols(int, char *[]);
84 static int rpc(int, char *[]);
85 static int services(int, char *[]);
86 static int shells(int, char *[]);
87 static int termcap(int, char *[]);
88
89 enum {
90 RV_OK = 0,
91 RV_USAGE = 1,
92 RV_NOTFOUND = 2,
93 RV_NOENUM = 3
94 };
95
96 static struct getentdb {
97 const char *name;
98 int (*callback)(int, char *[]);
99 } databases[] = {
100 { "disktab", disktab, },
101 { "ethers", ethers, },
102 { "gettytab", gettytab, },
103 { "group", group, },
104 { "hosts", hosts, },
105 { "networks", networks, },
106 { "passwd", passwd, },
107 { "princap", printcap, },
108 { "protocols", protocols, },
109 { "rpc", rpc, },
110 { "services", services, },
111 { "shells", shells, },
112 { "termcap", termcap, },
113
114 { NULL, NULL, },
115 };
116
117
118 int
119 main(int argc, char *argv[])
120 {
121 struct getentdb *curdb;
122
123 setprogname(argv[0]);
124
125 if (argc < 2)
126 usage();
127 for (curdb = databases; curdb->name != NULL; curdb++)
128 if (strcmp(curdb->name, argv[1]) == 0)
129 return (*curdb->callback)(argc, argv);
130
131 warn("Unknown database `%s'", argv[1]);
132 usage();
133 /* NOTREACHED */
134 }
135
136 static int
137 usage(void)
138 {
139 struct getentdb *curdb;
140
141 (void)fprintf(stderr, "Usage: %s database [key ...]\n",
142 getprogname());
143 (void)fprintf(stderr, " database may be one of:\n\t");
144 for (curdb = databases; curdb->name != NULL; curdb++)
145 (void)fprintf(stderr, " %s", curdb->name);
146 (void)fprintf(stderr, "\n");
147 exit(RV_USAGE);
148 /* NOTREACHED */
149 }
150
151 static int
152 parsenum(const char *word, unsigned long *result)
153 {
154 unsigned long num;
155 char *ep;
156
157 assert(word != NULL);
158 assert(result != NULL);
159
160 if (!isdigit((unsigned char)word[0]))
161 return 0;
162 errno = 0;
163 num = strtoul(word, &ep, 10);
164 if (num == ULONG_MAX && errno == ERANGE)
165 return 0;
166 if (*ep != '\0')
167 return 0;
168 *result = num;
169 return 1;
170 }
171
172 /*
173 * printfmtstrings --
174 * vprintf(format, ...),
175 * then the aliases (beginning with prefix, separated by sep),
176 * then a newline
177 */
178 static void
179 printfmtstrings(char *strings[], const char *prefix, const char *sep,
180 const char *fmt, ...)
181 {
182 va_list ap;
183 const char *curpref;
184 size_t i;
185
186 va_start(ap, fmt);
187 (void)vprintf(fmt, ap);
188 va_end(ap);
189
190 curpref = prefix;
191 for (i = 0; strings[i] != NULL; i++) {
192 (void)printf("%s%s", curpref, strings[i]);
193 curpref = sep;
194 }
195 (void)printf("\n");
196 }
197
198
199 /*
200 * ethers
201 */
202
203 static int
204 ethers(int argc, char *argv[])
205 {
206 char hostname[MAXHOSTNAMELEN + 1], *hp;
207 struct ether_addr ea, *eap;
208 int i, rv;
209
210 assert(argc > 1);
211 assert(argv != NULL);
212
213 #define ETHERSPRINT (void)printf("%-17s %s\n", ether_ntoa(eap), hp)
214
215 rv = RV_OK;
216 if (argc == 2) {
217 warnx("Enumeration not supported on ethers");
218 rv = RV_NOENUM;
219 } else {
220 for (i = 2; i < argc; i++) {
221 if ((eap = ether_aton(argv[i])) == NULL) {
222 eap = &ea;
223 hp = argv[i];
224 if (ether_hostton(hp, eap) != 0) {
225 rv = RV_NOTFOUND;
226 break;
227 }
228 } else {
229 hp = hostname;
230 if (ether_ntohost(hp, eap) != 0) {
231 rv = RV_NOTFOUND;
232 break;
233 }
234 }
235 ETHERSPRINT;
236 }
237 }
238 return rv;
239 }
240
241 /*
242 * group
243 */
244
245 static int
246 group(int argc, char *argv[])
247 {
248 struct group *gr;
249 unsigned long id;
250 int i, rv;
251
252 assert(argc > 1);
253 assert(argv != NULL);
254
255 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
256 gr->gr_name, gr->gr_passwd, gr->gr_gid)
257
258 (void)setgroupent(1);
259 rv = RV_OK;
260 if (argc == 2) {
261 while ((gr = getgrent()) != NULL)
262 GROUPPRINT;
263 } else {
264 for (i = 2; i < argc; i++) {
265 if (parsenum(argv[i], &id))
266 gr = getgrgid((gid_t)id);
267 else
268 gr = getgrnam(argv[i]);
269 if (gr != NULL)
270 GROUPPRINT;
271 else {
272 rv = RV_NOTFOUND;
273 break;
274 }
275 }
276 }
277 endgrent();
278 return rv;
279 }
280
281
282 /*
283 * hosts
284 */
285
286 static void
287 hostsprint(const struct hostent *he)
288 {
289 char buf[INET6_ADDRSTRLEN];
290
291 assert(he != NULL);
292 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
293 (void)strlcpy(buf, "# unknown", sizeof(buf));
294 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
295 }
296
297 static int
298 hosts(int argc, char *argv[])
299 {
300 struct hostent *he;
301 char addr[IN6ADDRSZ];
302 int i, rv;
303
304 assert(argc > 1);
305 assert(argv != NULL);
306
307 sethostent(1);
308 rv = RV_OK;
309 if (argc == 2) {
310 while ((he = gethostent()) != NULL)
311 hostsprint(he);
312 } else {
313 for (i = 2; i < argc; i++) {
314 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
315 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
316 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
317 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
318 else
319 he = gethostbyname(argv[i]);
320 if (he != NULL)
321 hostsprint(he);
322 else {
323 rv = RV_NOTFOUND;
324 break;
325 }
326 }
327 }
328 endhostent();
329 return rv;
330 }
331
332
333 /*
334 * networks
335 */
336
337 static void
338 networksprint(const struct netent *ne)
339 {
340 char buf[INET6_ADDRSTRLEN];
341 struct in_addr ianet;
342
343 assert(ne != NULL);
344 ianet = inet_makeaddr(ne->n_net, 0);
345 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
346 (void)strlcpy(buf, "# unknown", sizeof(buf));
347 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
348 }
349
350 static int
351 networks(int argc, char *argv[])
352 {
353 struct netent *ne;
354 in_addr_t net;
355 int i, rv;
356
357 assert(argc > 1);
358 assert(argv != NULL);
359
360 setnetent(1);
361 rv = RV_OK;
362 if (argc == 2) {
363 while ((ne = getnetent()) != NULL)
364 networksprint(ne);
365 } else {
366 for (i = 2; i < argc; i++) {
367 net = inet_network(argv[i]);
368 if (net != INADDR_NONE)
369 ne = getnetbyaddr(net, AF_INET);
370 else
371 ne = getnetbyname(argv[i]);
372 if (ne != NULL)
373 networksprint(ne);
374 else {
375 rv = RV_NOTFOUND;
376 break;
377 }
378 }
379 }
380 endnetent();
381 return rv;
382 }
383
384
385 /*
386 * passwd
387 */
388
389 static int
390 passwd(int argc, char *argv[])
391 {
392 struct passwd *pw;
393 unsigned long id;
394 int i, rv;
395
396 assert(argc > 1);
397 assert(argv != NULL);
398
399 #define PASSWDPRINT (void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
400 pw->pw_name, pw->pw_passwd, pw->pw_uid, \
401 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
402
403 (void)setpassent(1);
404 rv = RV_OK;
405 if (argc == 2) {
406 while ((pw = getpwent()) != NULL)
407 PASSWDPRINT;
408 } else {
409 for (i = 2; i < argc; i++) {
410 if (parsenum(argv[i], &id))
411 pw = getpwuid((uid_t)id);
412 else
413 pw = getpwnam(argv[i]);
414 if (pw != NULL)
415 PASSWDPRINT;
416 else {
417 rv = RV_NOTFOUND;
418 break;
419 }
420 }
421 }
422 endpwent();
423 return rv;
424 }
425
426 static char *
427 mygetent(const char * const * db_array, const char *name)
428 {
429 char *buf = NULL;
430 int error;
431
432 switch (error = cgetent(&buf, db_array, name)) {
433 case -3:
434 warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
435 break;
436 case -2:
437 warn("system error fetching record `%s' in `%s'", name,
438 db_array[0]);
439 break;
440 case -1:
441 case 0:
442 break;
443 case 1:
444 warnx("tc= reference not found in record for `%s' in `%s'",
445 name, db_array[0]);
446 break;
447 default:
448 warnx("unknown error %d in record `%s' in `%s'", error, name,
449 db_array[0]);
450 break;
451 }
452 return buf;
453 }
454
455 static char *
456 mygetone(const char * const * db_array, int first)
457 {
458 char *buf = NULL;
459 int error;
460
461 switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
462 case -2:
463 warnx("tc= loop in `%s'", db_array[0]);
464 break;
465 case -1:
466 warn("system error fetching record in `%s'", db_array[0]);
467 break;
468 case 0:
469 case 1:
470 break;
471 case 2:
472 warnx("tc= reference not found in `%s'", db_array[0]);
473 break;
474 default:
475 warnx("unknown error %d in `%s'", error, db_array[0]);
476 break;
477 }
478 return buf;
479 }
480
481 static void
482 capprint(const char *cap)
483 {
484 char *c = strchr(cap, ':');
485 if (c)
486 if (c == cap)
487 (void)printf("true\n");
488 else {
489 int l = (int)(c - cap);
490 (void)printf("%*.*s\n", l, l, cap);
491 }
492 else
493 (void)printf("%s\n", cap);
494 }
495
496 static void
497 prettyprint(char *b)
498 {
499 #define TERMWIDTH 65
500 int did = 0;
501 size_t len;
502 char *s, c;
503
504 for (;;) {
505 len = strlen(b);
506 if (len <= TERMWIDTH) {
507 done:
508 if (did)
509 printf("\t:");
510 printf("%s\n", b);
511 return;
512 }
513 for (s = b + TERMWIDTH; s > b && *s != ':'; s--)
514 continue;
515 if (*s++ != ':')
516 goto done;
517 c = *s;
518 *s = '\0';
519 if (did)
520 printf("\t:");
521 did++;
522 printf("%s\\\n", b);
523 *s = c;
524 b = s;
525 }
526 }
527
528 static void
529 handleone(const char * const *db_array, char *b, int recurse, int pretty,
530 int level)
531 {
532 char *tc;
533
534 if (level && pretty)
535 printf("\n");
536 if (pretty)
537 prettyprint(b);
538 else
539 printf("%s\n", b);
540 if (!recurse || cgetstr(b, "tc", &tc) <= 0)
541 return;
542
543 b = mygetent(db_array, tc);
544 free(tc);
545
546 if (b == NULL)
547 return;
548
549 handleone(db_array, b, recurse, pretty, ++level);
550 free(b);
551 }
552
553 static int
554 handlecap(const char *db, int argc, char *argv[])
555 {
556 static const char sfx[] = "=#:";
557 const char *db_array[] = { db, NULL };
558 char *b, *cap;
559 int i, j, rv, c;
560 int expand = 1, recurse = 0, pretty = 0;
561
562 assert(argc > 1);
563 assert(argv != NULL);
564
565 argc--;
566 argv++;
567 while ((c = getopt(argc, argv, "pnr")) != -1)
568 switch (c) {
569 case 'n':
570 expand = 0;
571 break;
572 case 'r':
573 expand = 0;
574 recurse = 1;
575 break;
576 case 'p':
577 pretty = 1;
578 break;
579 default:
580 usage();
581 break;
582 }
583
584 argc -= optind;
585 argv += optind;
586 csetexpandtc(expand);
587 rv = RV_OK;
588 if (argc == 0) {
589 for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
590 handleone(db_array, b, recurse, pretty, 0);
591 free(b);
592 }
593 } else {
594 if ((b = mygetent(db_array, argv[0])) == NULL)
595 return RV_NOTFOUND;
596 if (argc == 1)
597 handleone(db_array, b, recurse, pretty, 0);
598 else {
599 for (i = 2; i < argc; i++) {
600 for (j = 0; j < sizeof(sfx) - 1; j++) {
601 cap = cgetcap(b, argv[i], sfx[j]);
602 if (cap) {
603 capprint(cap);
604 break;
605 }
606 }
607 if (j == sizeof(sfx) - 1)
608 printf("false\n");
609 }
610 }
611 free(b);
612 }
613 return rv;
614 }
615
616 /*
617 * gettytab
618 */
619
620 static int
621 gettytab(int argc, char *argv[])
622 {
623 return handlecap(_PATH_GETTYTAB, argc, argv);
624 }
625
626 /*
627 * printcap
628 */
629
630 static int
631 printcap(int argc, char *argv[])
632 {
633 return handlecap(_PATH_PRINTCAP, argc, argv);
634 }
635
636 /*
637 * disktab
638 */
639
640 static int
641 disktab(int argc, char *argv[])
642 {
643 return handlecap(_PATH_DISKTAB, argc, argv);
644 }
645
646 /*
647 * termcap
648 */
649
650 static int
651 termcap(int argc, char *argv[])
652 {
653 return handlecap(_PATH_TERMCAP, argc, argv);
654 }
655 /*
656 * protocols
657 */
658
659 static int
660 protocols(int argc, char *argv[])
661 {
662 struct protoent *pe;
663 unsigned long id;
664 int i, rv;
665
666 assert(argc > 1);
667 assert(argv != NULL);
668
669 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \
670 "%-16s %5d", pe->p_name, pe->p_proto)
671
672 setprotoent(1);
673 rv = RV_OK;
674 if (argc == 2) {
675 while ((pe = getprotoent()) != NULL)
676 PROTOCOLSPRINT;
677 } else {
678 for (i = 2; i < argc; i++) {
679 if (parsenum(argv[i], &id))
680 pe = getprotobynumber((int)id);
681 else
682 pe = getprotobyname(argv[i]);
683 if (pe != NULL)
684 PROTOCOLSPRINT;
685 else {
686 rv = RV_NOTFOUND;
687 break;
688 }
689 }
690 }
691 endprotoent();
692 return rv;
693 }
694
695 /*
696 * rpc
697 */
698
699 static int
700 rpc(int argc, char *argv[])
701 {
702 struct rpcent *re;
703 unsigned long id;
704 int i, rv;
705
706 assert(argc > 1);
707 assert(argv != NULL);
708
709 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \
710 "%-16s %6d", \
711 re->r_name, re->r_number)
712
713 setrpcent(1);
714 rv = RV_OK;
715 if (argc == 2) {
716 while ((re = getrpcent()) != NULL)
717 RPCPRINT;
718 } else {
719 for (i = 2; i < argc; i++) {
720 if (parsenum(argv[i], &id))
721 re = getrpcbynumber((int)id);
722 else
723 re = getrpcbyname(argv[i]);
724 if (re != NULL)
725 RPCPRINT;
726 else {
727 rv = RV_NOTFOUND;
728 break;
729 }
730 }
731 }
732 endrpcent();
733 return rv;
734 }
735
736 /*
737 * services
738 */
739
740 static int
741 services(int argc, char *argv[])
742 {
743 struct servent *se;
744 unsigned long id;
745 char *proto;
746 int i, rv;
747
748 assert(argc > 1);
749 assert(argv != NULL);
750
751 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \
752 "%-16s %5d/%s", \
753 se->s_name, ntohs(se->s_port), se->s_proto)
754
755 setservent(1);
756 rv = RV_OK;
757 if (argc == 2) {
758 while ((se = getservent()) != NULL)
759 SERVICESPRINT;
760 } else {
761 for (i = 2; i < argc; i++) {
762 proto = strchr(argv[i], '/');
763 if (proto != NULL)
764 *proto++ = '\0';
765 if (parsenum(argv[i], &id))
766 se = getservbyport(htons(id), proto);
767 else
768 se = getservbyname(argv[i], proto);
769 if (se != NULL)
770 SERVICESPRINT;
771 else {
772 rv = RV_NOTFOUND;
773 break;
774 }
775 }
776 }
777 endservent();
778 return rv;
779 }
780
781
782 /*
783 * shells
784 */
785
786 static int
787 shells(int argc, char *argv[])
788 {
789 const char *sh;
790 int i, rv;
791
792 assert(argc > 1);
793 assert(argv != NULL);
794
795 #define SHELLSPRINT (void)printf("%s\n", sh)
796
797 setusershell();
798 rv = RV_OK;
799 if (argc == 2) {
800 while ((sh = getusershell()) != NULL)
801 SHELLSPRINT;
802 } else {
803 for (i = 2; i < argc; i++) {
804 setusershell();
805 while ((sh = getusershell()) != NULL) {
806 if (strcmp(sh, argv[i]) == 0) {
807 SHELLSPRINT;
808 break;
809 }
810 }
811 if (sh == NULL) {
812 rv = RV_NOTFOUND;
813 break;
814 }
815 }
816 }
817 endusershell();
818 return rv;
819 }
820