05ac095718d399345677697b8ad9c72ee837e57b
[dragonfly.git] / usr.bin / getent / getent.c
1 /*-
2  * Copyright (c) 2004 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  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the NetBSD
19  *      Foundation, Inc. and its contributors.
20  * 4. Neither the name of The NetBSD Foundation nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $
37  * $DragonFly: src/usr.bin/getent/getent.c,v 1.1 2007/12/04 18:13:09 dillon Exp $
38  */
39
40 #include <sys/socket.h>
41 #include <sys/param.h>
42 #include <arpa/inet.h>
43 #include <arpa/nameser.h>
44 #include <net/if.h>
45 #include <netinet/if_ether.h>
46 #include <netinet/in.h>         /* for INET6_ADDRSTRLEN */
47 #include <rpc/rpc.h>
48
49 #include <assert.h>
50 #include <ctype.h>
51 #include <errno.h>
52 #include <grp.h>
53 #include <limits.h>
54 #include <netdb.h>
55 #include <pwd.h>
56 #include <stdio.h>
57 #include <stdarg.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 static int      usage(void);
63 static int      parsenum(const char *, unsigned long *);
64 static int      ethers(int, char *[]);
65 static int      group(int, char *[]);
66 static int      hosts(int, char *[]);
67 static int      networks(int, char *[]);
68 static int      passwd(int, char *[]);
69 static int      protocols(int, char *[]);
70 static int      rpc(int, char *[]);
71 static int      services(int, char *[]);
72 static int      shells(int, char *[]);
73
74 enum {
75         RV_OK           = 0,
76         RV_USAGE        = 1,
77         RV_NOTFOUND     = 2,
78         RV_NOENUM       = 3
79 };
80
81 static struct getentdb {
82         const char      *name;
83         int             (*callback)(int, char *[]);
84 } databases[] = {
85         {       "ethers",       ethers,         },
86         {       "group",        group,          },
87         {       "hosts",        hosts,          },
88         {       "networks",     networks,       },
89         {       "passwd",       passwd,         },
90         {       "protocols",    protocols,      },
91         {       "rpc",          rpc,            },
92         {       "services",     services,       },
93         {       "shells",       shells,         },
94
95         {       NULL,           NULL,           },
96 };
97
98 int
99 main(int argc, char *argv[])
100 {
101         struct getentdb *curdb;
102
103         setprogname(argv[0]);
104
105         if (argc < 2)
106                 usage();
107         for (curdb = databases; curdb->name != NULL; curdb++) {
108                 if (strcmp(curdb->name, argv[1]) == 0) {
109                         exit(curdb->callback(argc, argv));
110                 }
111         }
112         fprintf(stderr, "Unknown database: %s\n", argv[1]);
113         usage();
114         /* NOTREACHED */
115         return RV_USAGE;
116 }
117
118 static int
119 usage(void)
120 {
121         struct getentdb *curdb;
122
123         fprintf(stderr, "Usage: %s database [key ...]\n",
124             getprogname());
125         fprintf(stderr, "       database may be one of:\n\t");
126         for (curdb = databases; curdb->name != NULL; curdb++) {
127                 fprintf(stderr, " %s", curdb->name);
128         }
129         fprintf(stderr, "\n");
130         exit(RV_USAGE);
131         /* NOTREACHED */
132 }
133
134 static int
135 parsenum(const char *word, unsigned long *result)
136 {
137         unsigned long   num;
138         char            *ep;
139
140         assert(word != NULL);
141         assert(result != NULL);
142
143         if (!isdigit((unsigned char)word[0]))
144                 return 0;
145         errno = 0;
146         num = strtoul(word, &ep, 10);
147         if (num == ULONG_MAX && errno == ERANGE)
148                 return 0;
149         if (*ep != '\0')
150                 return 0;
151         *result = num;
152         return 1;
153 }
154
155 /*
156  * printfmtstrings --
157  *      vprintf(format, ...),
158  *      then the aliases (beginning with prefix, separated by sep),
159  *      then a newline
160  */
161 static void
162 printfmtstrings(char *strings[], const char *prefix, const char *sep,
163         const char *fmt, ...)
164 {
165         va_list         ap;
166         const char      *curpref;
167         int             i;
168
169         va_start(ap, fmt);
170         vprintf(fmt, ap);
171
172         curpref = prefix;
173         for (i = 0; strings[i] != NULL; i++) {
174                 printf("%s%s", curpref, strings[i]);
175                 curpref = sep;
176         }
177         printf("\n");
178         va_end(ap);
179 }
180
181 /*
182  * ethers
183  */
184 static int
185 ethers(int argc, char *argv[])
186 {
187         char            hostname[MAXHOSTNAMELEN + 1], *hp;
188         struct ether_addr ea, *eap;
189         int             i, rv;
190
191         assert(argc > 1);
192         assert(argv != NULL);
193
194 #define ETHERSPRINT     printf("%-17s  %s\n", ether_ntoa(eap), hp)
195
196         rv = RV_OK;
197         if (argc == 2) {
198                 fprintf(stderr, "Enumeration not supported on ethers\n");
199                 rv = RV_NOENUM;
200         } else {
201                 for (i = 2; i < argc; i++) {
202                         if ((eap = ether_aton(argv[i])) == NULL) {
203                                 eap = &ea;
204                                 hp = argv[i];
205                                 if (ether_hostton(hp, eap) != 0) {
206                                         rv = RV_NOTFOUND;
207                                         break;
208                                 }
209                         } else {
210                                 hp = hostname;
211                                 if (ether_ntohost(hp, eap) != 0) {
212                                         rv = RV_NOTFOUND;
213                                         break;
214                                 }
215                         }
216                         ETHERSPRINT;
217                 }
218         }
219         return rv;
220 }
221
222 /*
223  * group
224  */
225
226 static int
227 group(int argc, char *argv[])
228 {
229         struct group    *gr;
230         unsigned long   id;
231         int             i, rv;
232
233         assert(argc > 1);
234         assert(argv != NULL);
235
236 #define GROUPPRINT      printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
237                             gr->gr_name, gr->gr_passwd, gr->gr_gid)
238
239         setgroupent(1);
240         rv = RV_OK;
241         if (argc == 2) {
242                 while ((gr = getgrent()) != NULL)
243                         GROUPPRINT;
244         } else {
245                 for (i = 2; i < argc; i++) {
246                         if (parsenum(argv[i], &id))
247                                 gr = getgrgid((gid_t)id);
248                         else
249                                 gr = getgrnam(argv[i]);
250                         if (gr != NULL)
251                                 GROUPPRINT;
252                         else {
253                                 rv = RV_NOTFOUND;
254                                 break;
255                         }
256                 }
257         }
258         endgrent();
259         return rv;
260 }
261
262
263 /*
264  * hosts
265  */
266
267 static void
268 hostsprint(const struct hostent *he)
269 {
270         char    buf[INET6_ADDRSTRLEN];
271
272         assert(he != NULL);
273         if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
274                 strlcpy(buf, "# unknown", sizeof(buf));
275         printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
276 }
277
278 static int
279 hosts(int argc, char *argv[])
280 {
281         struct hostent  *he;
282         char            addr[IN6ADDRSZ];
283         int             i, rv;
284
285         assert(argc > 1);
286         assert(argv != NULL);
287
288         sethostent(1);
289         rv = RV_OK;
290         if (argc == 2) {
291                 while ((he = gethostent()) != NULL)
292                         hostsprint(he);
293         } else {
294                 for (i = 2; i < argc; i++) {
295                         if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0)
296                                 he = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
297                         else if (inet_pton(AF_INET, argv[i], (void *)addr) > 0)
298                                 he = gethostbyaddr(addr, INADDRSZ, AF_INET);
299                         else
300                                 he = gethostbyname(argv[i]);
301                         if (he != NULL)
302                                 hostsprint(he);
303                         else {
304                                 rv = RV_NOTFOUND;
305                                 break;
306                         }
307                 }
308         }
309         endhostent();
310         return rv;
311 }
312
313 /*
314  * networks
315  */
316 static void
317 networksprint(const struct netent *ne)
318 {
319         char            buf[INET6_ADDRSTRLEN];
320         struct  in_addr ianet;
321
322         assert(ne != NULL);
323         ianet = inet_makeaddr(ne->n_net, 0);
324         if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
325                 strlcpy(buf, "# unknown", sizeof(buf));
326         printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
327 }
328
329 static int
330 networks(int argc, char *argv[])
331 {
332         struct netent   *ne;
333         in_addr_t       net;
334         int             i, rv;
335
336         assert(argc > 1);
337         assert(argv != NULL);
338
339         setnetent(1);
340         rv = RV_OK;
341         if (argc == 2) {
342                 while ((ne = getnetent()) != NULL)
343                         networksprint(ne);
344         } else {
345                 for (i = 2; i < argc; i++) {
346                         net = inet_network(argv[i]);
347                         if (net != INADDR_NONE)
348                                 ne = getnetbyaddr(net, AF_INET);
349                         else
350                                 ne = getnetbyname(argv[i]);
351                         if (ne != NULL)
352                                 networksprint(ne);
353                         else {
354                                 rv = RV_NOTFOUND;
355                                 break;
356                         }
357                 }
358         }
359         endnetent();
360         return rv;
361 }
362
363 /*
364  * passwd
365  */
366 static int
367 passwd(int argc, char *argv[])
368 {
369         struct passwd   *pw;
370         unsigned long   id;
371         int             i, rv;
372
373         assert(argc > 1);
374         assert(argv != NULL);
375
376 #define PASSWDPRINT     printf("%s:%s:%u:%u:%s:%s:%s\n", \
377                             pw->pw_name, pw->pw_passwd, pw->pw_uid, \
378                             pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
379
380         setpassent(1);
381         rv = RV_OK;
382         if (argc == 2) {
383                 while ((pw = getpwent()) != NULL)
384                         PASSWDPRINT;
385         } else {
386                 for (i = 2; i < argc; i++) {
387                         if (parsenum(argv[i], &id))
388                                 pw = getpwuid((uid_t)id);
389                         else
390                                 pw = getpwnam(argv[i]);
391                         if (pw != NULL)
392                                 PASSWDPRINT;
393                         else {
394                                 rv = RV_NOTFOUND;
395                                 break;
396                         }
397                 }
398         }
399         endpwent();
400         return rv;
401 }
402
403 /*
404  * protocols
405  */
406 static int
407 protocols(int argc, char *argv[])
408 {
409         struct protoent *pe;
410         unsigned long   id;
411         int             i, rv;
412
413         assert(argc > 1);
414         assert(argv != NULL);
415
416 #define PROTOCOLSPRINT  printfmtstrings(pe->p_aliases, "  ", " ", \
417                             "%-16s  %5d", pe->p_name, pe->p_proto)
418
419         setprotoent(1);
420         rv = RV_OK;
421         if (argc == 2) {
422                 while ((pe = getprotoent()) != NULL)
423                         PROTOCOLSPRINT;
424         } else {
425                 for (i = 2; i < argc; i++) {
426                         if (parsenum(argv[i], &id))
427                                 pe = getprotobynumber((int)id);
428                         else
429                                 pe = getprotobyname(argv[i]);
430                         if (pe != NULL)
431                                 PROTOCOLSPRINT;
432                         else {
433                                 rv = RV_NOTFOUND;
434                                 break;
435                         }
436                 }
437         }
438         endprotoent();
439         return rv;
440 }
441
442 /*
443  * rpc
444  */
445 static int
446 rpc(int argc, char *argv[])
447 {
448         struct rpcent   *re;
449         unsigned long   id;
450         int             i, rv;
451
452         assert(argc > 1);
453         assert(argv != NULL);
454
455 #define RPCPRINT        printfmtstrings(re->r_aliases, "  ", " ", \
456                                 "%-16s  %6d", \
457                                 re->r_name, re->r_number)
458
459         setrpcent(1);
460         rv = RV_OK;
461         if (argc == 2) {
462                 while ((re = getrpcent()) != NULL)
463                         RPCPRINT;
464         } else {
465                 for (i = 2; i < argc; i++) {
466                         if (parsenum(argv[i], &id))
467                                 re = getrpcbynumber((int)id);
468                         else
469                                 re = getrpcbyname(argv[i]);
470                         if (re != NULL)
471                                 RPCPRINT;
472                         else {
473                                 rv = RV_NOTFOUND;
474                                 break;
475                         }
476                 }
477         }
478         endrpcent();
479         return rv;
480 }
481
482 /*
483  * services
484  */
485 static int
486 services(int argc, char *argv[])
487 {
488         struct servent  *se;
489         unsigned long   id;
490         char            *proto;
491         int             i, rv;
492
493         assert(argc > 1);
494         assert(argv != NULL);
495
496 #define SERVICESPRINT   printfmtstrings(se->s_aliases, "  ", " ", \
497                             "%-16s  %5d/%s", \
498                             se->s_name, ntohs(se->s_port), se->s_proto)
499
500         setservent(1);
501         rv = RV_OK;
502         if (argc == 2) {
503                 while ((se = getservent()) != NULL)
504                         SERVICESPRINT;
505         } else {
506                 for (i = 2; i < argc; i++) {
507                         proto = strchr(argv[i], '/');
508                         if (proto != NULL)
509                                 *proto++ = '\0';
510                         if (parsenum(argv[i], &id))
511                                 se = getservbyport(htons((u_short)id), proto);
512                         else
513                                 se = getservbyname(argv[i], proto);
514                         if (se != NULL)
515                                 SERVICESPRINT;
516                         else {
517                                 rv = RV_NOTFOUND;
518                                 break;
519                         }
520                 }
521         }
522         endservent();
523         return rv;
524 }
525
526 /*
527  * shells
528  */
529 static int
530 shells(int argc, char *argv[])
531 {
532         const char      *sh;
533         int             i, rv;
534
535         assert(argc > 1);
536         assert(argv != NULL);
537
538 #define SHELLSPRINT     printf("%s\n", sh)
539
540         setusershell();
541         rv = RV_OK;
542         if (argc == 2) {
543                 while ((sh = getusershell()) != NULL)
544                         SHELLSPRINT;
545         } else {
546                 for (i = 2; i < argc; i++) {
547                         setusershell();
548                         while ((sh = getusershell()) != NULL) {
549                                 if (strcmp(sh, argv[i]) == 0) {
550                                         SHELLSPRINT;
551                                         break;
552                                 }
553                         }
554                         if (sh == NULL) {
555                                 rv = RV_NOTFOUND;
556                                 break;
557                         }
558                 }
559         }
560         endusershell();
561         return rv;
562 }