getent.c revision 1.9 1 /* $NetBSD: getent.c,v 1.9 2006/08/27 06:58:55 simonb 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.9 2006/08/27 06:58:55 simonb 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
59 #include <arpa/inet.h>
60 #include <arpa/nameser.h>
61
62 #include <net/if.h>
63 #include <net/if_ether.h>
64
65 #include <netinet/in.h> /* for INET6_ADDRSTRLEN */
66
67 #include <rpc/rpcent.h>
68
69 static int usage(void);
70 static int parsenum(const char *, unsigned long *);
71 static int ethers(int, char *[]);
72 static int group(int, char *[]);
73 static int hosts(int, char *[]);
74 static int networks(int, char *[]);
75 static int passwd(int, char *[]);
76 static int protocols(int, char *[]);
77 static int rpc(int, char *[]);
78 static int services(int, char *[]);
79 static int shells(int, char *[]);
80
81 enum {
82 RV_OK = 0,
83 RV_USAGE = 1,
84 RV_NOTFOUND = 2,
85 RV_NOENUM = 3,
86 };
87
88 static struct getentdb {
89 const char *name;
90 int (*callback)(int, char *[]);
91 } databases[] = {
92 { "ethers", ethers, },
93 { "group", group, },
94 { "hosts", hosts, },
95 { "networks", networks, },
96 { "passwd", passwd, },
97 { "protocols", protocols, },
98 { "rpc", rpc, },
99 { "services", services, },
100 { "shells", shells, },
101
102 { NULL, NULL, },
103 };
104
105
106 int
107 main(int argc, char *argv[])
108 {
109 struct getentdb *curdb;
110
111 setprogname(argv[0]);
112
113 if (argc < 2)
114 usage();
115 for (curdb = databases; curdb->name != NULL; curdb++) {
116 if (strcmp(curdb->name, argv[1]) == 0) {
117 exit(curdb->callback(argc, argv));
118 break;
119 }
120 }
121 fprintf(stderr, "Unknown database: %s\n", argv[1]);
122 usage();
123 /* NOTREACHED */
124 return RV_USAGE;
125 }
126
127 static int
128 usage(void)
129 {
130 struct getentdb *curdb;
131
132 fprintf(stderr, "Usage: %s database [key ...]\n",
133 getprogname());
134 fprintf(stderr, " database may be one of:\n\t");
135 for (curdb = databases; curdb->name != NULL; curdb++) {
136 fprintf(stderr, " %s", curdb->name);
137 }
138 fprintf(stderr, "\n");
139 exit(RV_USAGE);
140 /* NOTREACHED */
141 }
142
143 static int
144 parsenum(const char *word, unsigned long *result)
145 {
146 unsigned long num;
147 char *ep;
148
149 assert(word != NULL);
150 assert(result != NULL);
151
152 if (!isdigit((unsigned char)word[0]))
153 return 0;
154 errno = 0;
155 num = strtoul(word, &ep, 10);
156 if (num == ULONG_MAX && errno == ERANGE)
157 return 0;
158 if (*ep != '\0')
159 return 0;
160 *result = num;
161 return 1;
162 }
163
164 /*
165 * printfmtstrings --
166 * vprintf(format, ...),
167 * then the aliases (beginning with prefix, separated by sep),
168 * then a newline
169 */
170 static void
171 printfmtstrings(char *strings[], const char *prefix, const char *sep,
172 const char *fmt, ...)
173 {
174 va_list ap;
175 const char *curpref;
176 int i;
177
178 va_start(ap, fmt);
179 vprintf(fmt, ap);
180
181 curpref = prefix;
182 for (i = 0; strings[i] != NULL; i++) {
183 printf("%s%s", curpref, strings[i]);
184 curpref = sep;
185 }
186 printf("\n");
187 }
188
189
190 /*
191 * ethers
192 */
193
194 static int
195 ethers(int argc, char *argv[])
196 {
197 char hostname[MAXHOSTNAMELEN + 1], *hp;
198 struct ether_addr ea, *eap;
199 int i, rv;
200
201 assert(argc > 1);
202 assert(argv != NULL);
203
204 #define ETHERSPRINT printf("%-17s %s\n", ether_ntoa(eap), hp)
205
206 rv = RV_OK;
207 if (argc == 2) {
208 fprintf(stderr, "Enumeration not supported on ethers\n");
209 rv = RV_NOENUM;
210 } else {
211 for (i = 2; i < argc; i++) {
212 if ((eap = ether_aton(argv[i])) == NULL) {
213 eap = &ea;
214 hp = argv[i];
215 if (ether_hostton(hp, eap) != 0) {
216 rv = RV_NOTFOUND;
217 break;
218 }
219 } else {
220 hp = hostname;
221 if (ether_ntohost(hp, eap) != 0) {
222 rv = RV_NOTFOUND;
223 break;
224 }
225 }
226 ETHERSPRINT;
227 }
228 }
229 return rv;
230 }
231
232 /*
233 * group
234 */
235
236 static int
237 group(int argc, char *argv[])
238 {
239 struct group *gr;
240 unsigned long id;
241 int i, rv;
242
243 assert(argc > 1);
244 assert(argv != NULL);
245
246 #define GROUPPRINT printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
247 gr->gr_name, gr->gr_passwd, gr->gr_gid)
248
249 setgroupent(1);
250 rv = RV_OK;
251 if (argc == 2) {
252 while ((gr = getgrent()) != NULL)
253 GROUPPRINT;
254 } else {
255 for (i = 2; i < argc; i++) {
256 if (parsenum(argv[i], &id))
257 gr = getgrgid(id);
258 else
259 gr = getgrnam(argv[i]);
260 if (gr != NULL)
261 GROUPPRINT;
262 else {
263 rv = RV_NOTFOUND;
264 break;
265 }
266 }
267 }
268 endgrent();
269 return rv;
270 }
271
272
273 /*
274 * hosts
275 */
276
277 static void
278 hostsprint(const struct hostent *he)
279 {
280 char buf[INET6_ADDRSTRLEN];
281
282 assert(he != NULL);
283 if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
284 strlcpy(buf, "# unknown", sizeof(buf));
285 printfmtstrings(he->h_aliases, " ", " ", "%-16s %s", buf, he->h_name);
286 }
287
288 static int
289 hosts(int argc, char *argv[])
290 {
291 struct hostent *he;
292 char addr[IN6ADDRSZ];
293 int i, rv;
294
295 assert(argc > 1);
296 assert(argv != NULL);
297
298 sethostent(1);
299 rv = RV_OK;
300 if (argc == 2) {
301 while ((he = gethostent()) != NULL)
302 hostsprint(he);
303 } else {
304 for (i = 2; i < argc; i++) {
305 if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
306 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
307 else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
308 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
309 else
310 he = gethostbyname(argv[i]);
311 if (he != NULL)
312 hostsprint(he);
313 else {
314 rv = RV_NOTFOUND;
315 break;
316 }
317 }
318 }
319 endhostent();
320 return rv;
321 }
322
323
324 /*
325 * networks
326 */
327
328 static void
329 networksprint(const struct netent *ne)
330 {
331 char buf[INET6_ADDRSTRLEN];
332 struct in_addr ianet;
333
334 assert(ne != NULL);
335 ianet = inet_makeaddr(ne->n_net, 0);
336 if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
337 strlcpy(buf, "# unknown", sizeof(buf));
338 printfmtstrings(ne->n_aliases, " ", " ", "%-16s %s", ne->n_name, buf);
339 }
340
341 static int
342 networks(int argc, char *argv[])
343 {
344 struct netent *ne;
345 in_addr_t net;
346 int i, rv;
347
348 assert(argc > 1);
349 assert(argv != NULL);
350
351 setnetent(1);
352 rv = RV_OK;
353 if (argc == 2) {
354 while ((ne = getnetent()) != NULL)
355 networksprint(ne);
356 } else {
357 for (i = 2; i < argc; i++) {
358 net = inet_network(argv[i]);
359 if (net != INADDR_NONE)
360 ne = getnetbyaddr(net, AF_INET);
361 else
362 ne = getnetbyname(argv[i]);
363 if (ne != NULL)
364 networksprint(ne);
365 else {
366 rv = RV_NOTFOUND;
367 break;
368 }
369 }
370 }
371 endnetent();
372 return rv;
373 }
374
375
376 /*
377 * passwd
378 */
379
380 static int
381 passwd(int argc, char *argv[])
382 {
383 struct passwd *pw;
384 unsigned long id;
385 int i, rv;
386
387 assert(argc > 1);
388 assert(argv != NULL);
389
390 #define PASSWDPRINT printf("%s:%s:%u:%u:%s:%s:%s\n", \
391 pw->pw_name, pw->pw_passwd, pw->pw_uid, \
392 pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
393
394 setpassent(1);
395 rv = RV_OK;
396 if (argc == 2) {
397 while ((pw = getpwent()) != NULL)
398 PASSWDPRINT;
399 } else {
400 for (i = 2; i < argc; i++) {
401 if (parsenum(argv[i], &id))
402 pw = getpwuid(id);
403 else
404 pw = getpwnam(argv[i]);
405 if (pw != NULL)
406 PASSWDPRINT;
407 else {
408 rv = RV_NOTFOUND;
409 break;
410 }
411 }
412 }
413 endpwent();
414 return rv;
415 }
416
417
418 /*
419 * protocols
420 */
421
422 static int
423 protocols(int argc, char *argv[])
424 {
425 struct protoent *pe;
426 unsigned long id;
427 int i, rv;
428
429 assert(argc > 1);
430 assert(argv != NULL);
431
432 #define PROTOCOLSPRINT printfmtstrings(pe->p_aliases, " ", " ", \
433 "%-16s %5d", pe->p_name, pe->p_proto)
434
435 setprotoent(1);
436 rv = RV_OK;
437 if (argc == 2) {
438 while ((pe = getprotoent()) != NULL)
439 PROTOCOLSPRINT;
440 } else {
441 for (i = 2; i < argc; i++) {
442 if (parsenum(argv[i], &id))
443 pe = getprotobynumber(id);
444 else
445 pe = getprotobyname(argv[i]);
446 if (pe != NULL)
447 PROTOCOLSPRINT;
448 else {
449 rv = RV_NOTFOUND;
450 break;
451 }
452 }
453 }
454 endprotoent();
455 return rv;
456 }
457
458 /*
459 * rpc
460 */
461
462 static int
463 rpc(int argc, char *argv[])
464 {
465 struct rpcent *re;
466 unsigned long id;
467 int i, rv;
468
469 assert(argc > 1);
470 assert(argv != NULL);
471
472 #define RPCPRINT printfmtstrings(re->r_aliases, " ", " ", \
473 "%-16s %6d", \
474 re->r_name, re->r_number)
475
476 setrpcent(1);
477 rv = RV_OK;
478 if (argc == 2) {
479 while ((re = getrpcent()) != NULL)
480 RPCPRINT;
481 } else {
482 for (i = 2; i < argc; i++) {
483 if (parsenum(argv[i], &id))
484 re = getrpcbynumber(id);
485 else
486 re = getrpcbyname(argv[i]);
487 if (re != NULL)
488 RPCPRINT;
489 else {
490 rv = RV_NOTFOUND;
491 break;
492 }
493 }
494 }
495 endrpcent();
496 return rv;
497 }
498
499 /*
500 * services
501 */
502
503 static int
504 services(int argc, char *argv[])
505 {
506 struct servent *se;
507 unsigned long id;
508 char *proto;
509 int i, rv;
510
511 assert(argc > 1);
512 assert(argv != NULL);
513
514 #define SERVICESPRINT printfmtstrings(se->s_aliases, " ", " ", \
515 "%-16s %5d/%s", \
516 se->s_name, ntohs(se->s_port), se->s_proto)
517
518 setservent(1);
519 rv = RV_OK;
520 if (argc == 2) {
521 while ((se = getservent()) != NULL)
522 SERVICESPRINT;
523 } else {
524 for (i = 2; i < argc; i++) {
525 proto = strchr(argv[i], '/');
526 if (proto != NULL)
527 *proto++ = '\0';
528 if (parsenum(argv[i], &id))
529 se = getservbyport(htons(id), proto);
530 else
531 se = getservbyname(argv[i], proto);
532 if (se != NULL)
533 SERVICESPRINT;
534 else {
535 rv = RV_NOTFOUND;
536 break;
537 }
538 }
539 }
540 endservent();
541 return rv;
542 }
543
544
545 /*
546 * shells
547 */
548
549 static int
550 shells(int argc, char *argv[])
551 {
552 const char *sh;
553 int i, rv;
554
555 assert(argc > 1);
556 assert(argv != NULL);
557
558 #define SHELLSPRINT printf("%s\n", sh)
559
560 setusershell();
561 rv = RV_OK;
562 if (argc == 2) {
563 while ((sh = getusershell()) != NULL)
564 SHELLSPRINT;
565 } else {
566 for (i = 2; i < argc; i++) {
567 setusershell();
568 while ((sh = getusershell()) != NULL) {
569 if (strcmp(sh, argv[i]) == 0) {
570 SHELLSPRINT;
571 break;
572 }
573 }
574 if (sh == NULL) {
575 rv = RV_NOTFOUND;
576 break;
577 }
578 }
579 }
580 endusershell();
581 return rv;
582 }
583