getent.c revision 1.10 1 /* $NetBSD: getent.c,v 1.10 2008/02/01 22:39:21 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.10 2008/02/01 22:39:21 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 ethers(int, char *[]);
77 static int group(int, char *[]);
78 static int hosts(int, char *[]);
79 static int networks(int, char *[]);
80 static int passwd(int, char *[]);
81 static int printcap(int, char *[]);
82 static int protocols(int, char *[]);
83 static int rpc(int, char *[]);
84 static int services(int, char *[]);
85 static int shells(int, char *[]);
86 static int termcap(int, char *[]);
87
88 enum {
89 RV_OK = 0,
90 RV_USAGE = 1,
91 RV_NOTFOUND = 2,
92 RV_NOENUM = 3
93 };
94
95 static struct getentdb {
96 const char *name;
97 int (*callback)(int, char *[]);
98 } databases[] = {
99 { "disktab", disktab, },
100 { "ethers", ethers, },
101 { "group", group, },
102 { "hosts", hosts, },
103 { "networks", networks, },
104 { "passwd", passwd, },
105 { "princap", printcap, },
106 { "protocols", protocols, },
107 { "rpc", rpc, },
108 { "services", services, },
109 { "shells", shells, },
110 { "termcap", termcap, },
111
112 { NULL, NULL, },
113 };
114
115
116 int
117 main(int argc, char *argv[])
118 {
119 struct getentdb *curdb;
120
121 setprogname(argv[0]);
122
123 if (argc < 2)
124 usage();
125 for (curdb = databases; curdb->name != NULL; curdb++)
126 if (strcmp(curdb->name, argv[1]) == 0)
127 return (*curdb->callback)(argc, argv);
128
129 warn("Unknown database `%s'", argv[1]);
130 usage();
131 /* NOTREACHED */
132 }
133
134 static int
135 usage(void)
136 {
137 struct getentdb *curdb;
138
139 (void)fprintf(stderr, "Usage: %s database [key ...]\n",
140 getprogname());
141 (void)fprintf(stderr, " database may be one of:\n\t");
142 for (curdb = databases; curdb->name != NULL; curdb++)
143 (void)fprintf(stderr, " %s", curdb->name);
144 (void)fprintf(stderr, "\n");
145 exit(RV_USAGE);
146 /* NOTREACHED */
147 }
148
149 static int
150 parsenum(const char *word, unsigned long *result)
151 {
152 unsigned long num;
153 char *ep;
154
155 assert(word != NULL);
156 assert(result != NULL);
157
158 if (!isdigit((unsigned char)word[0]))
159 return 0;
160 errno = 0;
161 num = strtoul(word, &ep, 10);
162 if (num == ULONG_MAX && errno == ERANGE)
163 return 0;
164 if (*ep != '\0')
165 return 0;
166 *result = num;
167 return 1;
168 }
169
170 /*
171 * printfmtstrings --
172 * vprintf(format, ...),
173 * then the aliases (beginning with prefix, separated by sep),
174 * then a newline
175 */
176 static void
177 printfmtstrings(char *strings[], const char *prefix, const char *sep,
178 const char *fmt, ...)
179 {
180 va_list ap;
181 const char *curpref;
182 size_t i;
183
184 va_start(ap, fmt);
185 (void)vprintf(fmt, ap);
186 va_end(ap);
187
188 curpref = prefix;
189 for (i = 0; strings[i] != NULL; i++) {
190 (void)printf("%s%s", curpref, strings[i]);
191 curpref = sep;
192 }
193 (void)printf("\n");
194 }
195
196
197 /*
198 * ethers
199 */
200
201 static int
202 ethers(int argc, char *argv[])
203 {
204 char hostname[MAXHOSTNAMELEN + 1], *hp;
205 struct ether_addr ea, *eap;
206 int i, rv;
207
208 assert(argc > 1);
209 assert(argv != NULL);
210
211 #define ETHERSPRINT (void)printf("%-17s %s\n", ether_ntoa(eap), hp)
212
213 rv = RV_OK;
214 if (argc == 2) {
215 warnx("Enumeration not supported on ethers");
216 rv = RV_NOENUM;
217 } else {
218 for (i = 2; i < argc; i++) {
219 if ((eap = ether_aton(argv[i])) == NULL) {
220 eap = &ea;
221 hp = argv[i];
222 if (ether_hostton(hp, eap) != 0) {
223 rv = RV_NOTFOUND;
224 break;
225 }
226 } else {
227 hp = hostname;
228 if (ether_ntohost(hp, eap) != 0) {
229 rv = RV_NOTFOUND;
230 break;
231 }
232 }
233 ETHERSPRINT;
234 }
235 }
236 return rv;
237 }
238
239 /*
240 * group
241 */
242
243 static int
244 group(int argc, char *argv[])
245 {
246 struct group *gr;
247 unsigned long id;
248 int i, rv;
249
250 assert(argc > 1);
251 assert(argv != NULL);
252
253 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
254 gr->gr_name, gr->gr_passwd, gr->gr_gid)
255
256 (void)setgroupent(1);
257 rv = RV_OK;
258 if (argc == 2) {
259 while ((gr = getgrent()) != NULL)
260 GROUPPRINT;
261 } else {
262 for (i = 2; i < argc; i++) {
263 if (parsenum(argv[i], &id))
264 gr = getgrgid((gid_t)id);
265 else
266 gr = getgrnam(argv[i]);
267 if (gr != NULL)
268 GROUPPRINT;
269 else {
270 rv = RV_NOTFOUND;
271 break;
272 }
273 }
274 }
275 endgrent();
276 return rv;
277 }
278
279
280 /*
281 * hosts
282 */
283
284 static void
285 hostsprint(const struct hostent *he)
286 {
287 char buf[INET6_ADDRSTRLEN];
288
289 assert(he != NULL);
290 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
291 (void)strlcpy(buf, "# unknown", sizeof(buf));
292 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
293 }
294
295 static int
296 hosts(int argc, char *argv[])
297 {
298 struct hostent *he;
299 char addr[IN6ADDRSZ];
300 int i, rv;
301
302 assert(argc > 1);
303 assert(argv != NULL);
304
305 sethostent(1);
306 rv = RV_OK;
307 if (argc == 2) {
308 while ((he = gethostent()) != NULL)
309 hostsprint(he);
310 } else {
311 for (i = 2; i < argc; i++) {
312 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
313 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
314 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
315 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
316 else
317 he = gethostbyname(argv[i]);
318 if (he != NULL)
319 hostsprint(he);
320 else {
321 rv = RV_NOTFOUND;
322 break;
323 }
324 }
325 }
326 endhostent();
327 return rv;
328 }
329
330
331 /*
332 * networks
333 */
334
335 static void
336 networksprint(const struct netent *ne)
337 {
338 char buf[INET6_ADDRSTRLEN];
339 struct in_addr ianet;
340
341 assert(ne != NULL);
342 ianet = inet_makeaddr(ne->n_net, 0);
343 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
344 (void)strlcpy(buf, "# unknown", sizeof(buf));
345 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
346 }
347
348 static int
349 networks(int argc, char *argv[])
350 {
351 struct netent *ne;
352 in_addr_t net;
353 int i, rv;
354
355 assert(argc > 1);
356 assert(argv != NULL);
357
358 setnetent(1);
359 rv = RV_OK;
360 if (argc == 2) {
361 while ((ne = getnetent()) != NULL)
362 networksprint(ne);
363 } else {
364 for (i = 2; i < argc; i++) {
365 net = inet_network(argv[i]);
366 if (net != INADDR_NONE)
367 ne = getnetbyaddr(net, AF_INET);
368 else
369 ne = getnetbyname(argv[i]);
370 if (ne != NULL)
371 networksprint(ne);
372 else {
373 rv = RV_NOTFOUND;
374 break;
375 }
376 }
377 }
378 endnetent();
379 return rv;
380 }
381
382
383 /*
384 * passwd
385 */
386
387 static int
388 passwd(int argc, char *argv[])
389 {
390 struct passwd *pw;
391 unsigned long id;
392 int i, rv;
393
394 assert(argc > 1);
395 assert(argv != NULL);
396
397 #define PASSWDPRINT (void)printf("%s:%s:%u:%u:%s:%s:%s\n", \
398 pw->pw_name, pw->pw_passwd, pw->pw_uid, \
399 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
400
401 (void)setpassent(1);
402 rv = RV_OK;
403 if (argc == 2) {
404 while ((pw = getpwent()) != NULL)
405 PASSWDPRINT;
406 } else {
407 for (i = 2; i < argc; i++) {
408 if (parsenum(argv[i], &id))
409 pw = getpwuid((uid_t)id);
410 else
411 pw = getpwnam(argv[i]);
412 if (pw != NULL)
413 PASSWDPRINT;
414 else {
415 rv = RV_NOTFOUND;
416 break;
417 }
418 }
419 }
420 endpwent();
421 return rv;
422 }
423
424 static char *
425 mygetent(const char * const * db_array, const char *name)
426 {
427 char *buf = NULL;
428 int error;
429
430 switch (error = cgetent(&buf, db_array, name)) {
431 case -3:
432 warnx("tc= loop in record `%s' in `%s'", name, db_array[0]);
433 break;
434 case -2:
435 warn("system error fetching record `%s' in `%s'", name,
436 db_array[0]);
437 break;
438 case -1:
439 case 0:
440 break;
441 case 1:
442 warnx("tc= reference not found in record for `%s' in `%s'",
443 name, db_array[0]);
444 break;
445 default:
446 warnx("unknown error %d in record `%s' in `%s'", error, name,
447 db_array[0]);
448 break;
449 }
450 return buf;
451 }
452
453 static char *
454 mygetone(const char * const * db_array, int first)
455 {
456 char *buf = NULL;
457 int error;
458
459 switch (error = (first ? cgetfirst : cgetnext)(&buf, db_array)) {
460 case -2:
461 warnx("tc= loop in `%s'", db_array[0]);
462 break;
463 case -1:
464 warn("system error fetching record in `%s'", db_array[0]);
465 break;
466 case 0:
467 case 1:
468 break;
469 case 2:
470 warnx("tc= reference not found in `%s'", db_array[0]);
471 break;
472 default:
473 warnx("unknown error %d in `%s'", error, db_array[0]);
474 break;
475 }
476 return buf;
477 }
478
479 static void
480 capprint(const char *cap)
481 {
482 char *c = strchr(cap, ':');
483 if (c)
484 if (c == cap)
485 (void)printf("true\n");
486 else {
487 int l = (int)(c - cap);
488 (void)printf("%*.*s\n", l, l, cap);
489 }
490 else
491 (void)printf("%s\n", cap);
492 }
493
494 static int
495 handlecap(const char *db, int argc, char *argv[])
496 {
497 static const char sfx[] = "=#:";
498 const char *db_array[] = { db, NULL };
499 char *b, *cap;
500 int i, j, rv;
501
502 assert(argc > 1);
503 assert(argv != NULL);
504
505 rv = RV_OK;
506 if (argc == 2) {
507 for (b = mygetone(db_array, 1); b; b = mygetone(db_array, 0)) {
508 (void)printf("%s\n", b);
509 free(b);
510 }
511 } else {
512 if ((b = mygetent(db_array, argv[2])) == NULL)
513 return RV_NOTFOUND;
514 if (argc == 3)
515 (void)printf("%s\n", b);
516 else {
517 for (i = 3; i < argc; i++) {
518 for (j = 0; j < sizeof(sfx) - 1; j++) {
519 cap = cgetcap(b, argv[i], sfx[j]);
520 if (cap) {
521 capprint(cap);
522 break;
523 }
524 }
525 if (j == sizeof(sfx) - 1)
526 printf("false\n");
527 }
528 }
529 free(b);
530 }
531 return rv;
532 }
533
534 /*
535 * printcap
536 */
537
538 static int
539 printcap(int argc, char *argv[])
540 {
541 return handlecap(_PATH_PRINTCAP, argc, argv);
542 }
543
544 /*
545 * disktab
546 */
547
548 static int
549 disktab(int argc, char *argv[])
550 {
551 return handlecap(_PATH_DISKTAB, argc, argv);
552 }
553
554 /*
555 * termcap
556 */
557
558 static int
559 termcap(int argc, char *argv[])
560 {
561 return handlecap(_PATH_TERMCAP, argc, argv);
562 }
563 /*
564 * protocols
565 */
566
567 static int
568 protocols(int argc, char *argv[])
569 {
570 struct protoent *pe;
571 unsigned long id;
572 int i, rv;
573
574 assert(argc > 1);
575 assert(argv != NULL);
576
577 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \
578 "%-16s %5d", pe->p_name, pe->p_proto)
579
580 setprotoent(1);
581 rv = RV_OK;
582 if (argc == 2) {
583 while ((pe = getprotoent()) != NULL)
584 PROTOCOLSPRINT;
585 } else {
586 for (i = 2; i < argc; i++) {
587 if (parsenum(argv[i], &id))
588 pe = getprotobynumber((int)id);
589 else
590 pe = getprotobyname(argv[i]);
591 if (pe != NULL)
592 PROTOCOLSPRINT;
593 else {
594 rv = RV_NOTFOUND;
595 break;
596 }
597 }
598 }
599 endprotoent();
600 return rv;
601 }
602
603 /*
604 * rpc
605 */
606
607 static int
608 rpc(int argc, char *argv[])
609 {
610 struct rpcent *re;
611 unsigned long id;
612 int i, rv;
613
614 assert(argc > 1);
615 assert(argv != NULL);
616
617 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \
618 "%-16s %6d", \
619 re->r_name, re->r_number)
620
621 setrpcent(1);
622 rv = RV_OK;
623 if (argc == 2) {
624 while ((re = getrpcent()) != NULL)
625 RPCPRINT;
626 } else {
627 for (i = 2; i < argc; i++) {
628 if (parsenum(argv[i], &id))
629 re = getrpcbynumber((int)id);
630 else
631 re = getrpcbyname(argv[i]);
632 if (re != NULL)
633 RPCPRINT;
634 else {
635 rv = RV_NOTFOUND;
636 break;
637 }
638 }
639 }
640 endrpcent();
641 return rv;
642 }
643
644 /*
645 * services
646 */
647
648 static int
649 services(int argc, char *argv[])
650 {
651 struct servent *se;
652 unsigned long id;
653 char *proto;
654 int i, rv;
655
656 assert(argc > 1);
657 assert(argv != NULL);
658
659 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \
660 "%-16s %5d/%s", \
661 se->s_name, ntohs(se->s_port), se->s_proto)
662
663 setservent(1);
664 rv = RV_OK;
665 if (argc == 2) {
666 while ((se = getservent()) != NULL)
667 SERVICESPRINT;
668 } else {
669 for (i = 2; i < argc; i++) {
670 proto = strchr(argv[i], '/');
671 if (proto != NULL)
672 *proto++ = '\0';
673 if (parsenum(argv[i], &id))
674 se = getservbyport(htons(id), proto);
675 else
676 se = getservbyname(argv[i], proto);
677 if (se != NULL)
678 SERVICESPRINT;
679 else {
680 rv = RV_NOTFOUND;
681 break;
682 }
683 }
684 }
685 endservent();
686 return rv;
687 }
688
689
690 /*
691 * shells
692 */
693
694 static int
695 shells(int argc, char *argv[])
696 {
697 const char *sh;
698 int i, rv;
699
700 assert(argc > 1);
701 assert(argv != NULL);
702
703 #define SHELLSPRINT (void)printf("%s\n", sh)
704
705 setusershell();
706 rv = RV_OK;
707 if (argc == 2) {
708 while ((sh = getusershell()) != NULL)
709 SHELLSPRINT;
710 } else {
711 for (i = 2; i < argc; i++) {
712 setusershell();
713 while ((sh = getusershell()) != NULL) {
714 if (strcmp(sh, argv[i]) == 0) {
715 SHELLSPRINT;
716 break;
717 }
718 }
719 if (sh == NULL) {
720 rv = RV_NOTFOUND;
721 break;
722 }
723 }
724 }
725 endusershell();
726 return rv;
727 }
728