]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/getent/getent.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.bin / getent / getent.c
1 /*      $NetBSD: getent.c,v 1.7 2005/08/24 14:31:02 ginsbach Exp $      */
2
3 /*-
4  * Copyright (c) 2004 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <arpa/inet.h>
38 #include <arpa/nameser.h>
39 #include <net/if.h>
40 #include <netinet/if_ether.h>
41 #include <netinet/in.h>         /* for INET6_ADDRSTRLEN */
42 #include <rpc/rpcent.h>
43
44 #include <assert.h>
45 #include <ctype.h>
46 #include <errno.h>
47 #include <grp.h>
48 #include <limits.h>
49 #include <netdb.h>
50 #include <pwd.h>
51 #include <stdarg.h>
52 #include <stdint.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <utmpx.h>
58
59 static int      usage(void);
60 static int      parsenum(const char *, unsigned long *);
61 static int      ethers(int, char *[]);
62 static int      group(int, char *[]);
63 static int      hosts(int, char *[]);
64 static int      netgroup(int, char *[]);
65 static int      networks(int, char *[]);
66 static int      passwd(int, char *[]);
67 static int      protocols(int, char *[]);
68 static int      rpc(int, char *[]);
69 static int      services(int, char *[]);
70 static int      shells(int, char *[]);
71 static int      utmpx(int, char *[]);
72
73 enum {
74         RV_OK           = 0,
75         RV_USAGE        = 1,
76         RV_NOTFOUND     = 2,
77         RV_NOENUM       = 3
78 };
79
80 static struct getentdb {
81         const char      *name;
82         int             (*callback)(int, char *[]);
83 } databases[] = {
84         {       "ethers",       ethers,         },
85         {       "group",        group,          },
86         {       "hosts",        hosts,          },
87         {       "networks",     networks,       },
88         {       "passwd",       passwd,         },
89         {       "protocols",    protocols,      },
90         {       "rpc",          rpc,            },
91         {       "services",     services,       },
92         {       "shells",       shells,         },
93         {       "netgroup",     netgroup,       },
94         {       "utmpx",        utmpx,          },
95
96         {       NULL,           NULL,           },
97 };
98
99 int
100 main(int argc, char *argv[])
101 {
102         struct getentdb *curdb;
103
104         setprogname(argv[0]);
105
106         if (argc < 2)
107                 usage();
108         for (curdb = databases; curdb->name != NULL; curdb++) {
109                 if (strcmp(curdb->name, argv[1]) == 0) {
110                         exit(curdb->callback(argc, argv));
111                 }
112         }
113         fprintf(stderr, "Unknown database: %s\n", argv[1]);
114         usage();
115         /* NOTREACHED */
116         return RV_USAGE;
117 }
118
119 static int
120 usage(void)
121 {
122         struct getentdb *curdb;
123
124         fprintf(stderr, "Usage: %s database [key ...]\n",
125             getprogname());
126         fprintf(stderr, "       database may be one of:\n\t");
127         for (curdb = databases; curdb->name != NULL; curdb++) {
128                 fprintf(stderr, " %s", curdb->name);
129         }
130         fprintf(stderr, "\n");
131         exit(RV_USAGE);
132         /* NOTREACHED */
133 }
134
135 static int
136 parsenum(const char *word, unsigned long *result)
137 {
138         unsigned long   num;
139         char            *ep;
140
141         assert(word != NULL);
142         assert(result != NULL);
143
144         if (!isdigit((unsigned char)word[0]))
145                 return 0;
146         errno = 0;
147         num = strtoul(word, &ep, 10);
148         if (num == ULONG_MAX && errno == ERANGE)
149                 return 0;
150         if (*ep != '\0')
151                 return 0;
152         *result = num;
153         return 1;
154 }
155
156 /*
157  * printfmtstrings --
158  *      vprintf(format, ...),
159  *      then the aliases (beginning with prefix, separated by sep),
160  *      then a newline
161  */
162 static void
163 printfmtstrings(char *strings[], const char *prefix, const char *sep,
164         const char *fmt, ...)
165 {
166         va_list         ap;
167         const char      *curpref;
168         int             i;
169
170         va_start(ap, fmt);
171         vprintf(fmt, ap);
172
173         curpref = prefix;
174         for (i = 0; strings[i] != NULL; i++) {
175                 printf("%s%s", curpref, strings[i]);
176                 curpref = sep;
177         }
178         printf("\n");
179         va_end(ap);
180 }
181
182 /*
183  * ethers
184  */
185 static int
186 ethers(int argc, char *argv[])
187 {
188         char            hostname[MAXHOSTNAMELEN + 1], *hp;
189         struct ether_addr ea, *eap;
190         int             i, rv;
191
192         assert(argc > 1);
193         assert(argv != NULL);
194
195 #define ETHERSPRINT     printf("%-17s  %s\n", ether_ntoa(eap), hp)
196
197         rv = RV_OK;
198         if (argc == 2) {
199                 fprintf(stderr, "Enumeration not supported on ethers\n");
200                 rv = RV_NOENUM;
201         } else {
202                 for (i = 2; i < argc; i++) {
203                         if ((eap = ether_aton(argv[i])) == NULL) {
204                                 eap = &ea;
205                                 hp = argv[i];
206                                 if (ether_hostton(hp, eap) != 0) {
207                                         rv = RV_NOTFOUND;
208                                         break;
209                                 }
210                         } else {
211                                 hp = hostname;
212                                 if (ether_ntohost(hp, eap) != 0) {
213                                         rv = RV_NOTFOUND;
214                                         break;
215                                 }
216                         }
217                         ETHERSPRINT;
218                 }
219         }
220         return rv;
221 }
222
223 /*
224  * group
225  */
226
227 static int
228 group(int argc, char *argv[])
229 {
230         struct group    *gr;
231         unsigned long   id;
232         int             i, rv;
233
234         assert(argc > 1);
235         assert(argv != NULL);
236
237 #define GROUPPRINT      printfmtstrings(gr->gr_mem, ":", ",", "%s:%s:%u", \
238                             gr->gr_name, gr->gr_passwd, gr->gr_gid)
239
240         setgroupent(1);
241         rv = RV_OK;
242         if (argc == 2) {
243                 while ((gr = getgrent()) != NULL)
244                         GROUPPRINT;
245         } else {
246                 for (i = 2; i < argc; i++) {
247                         if (parsenum(argv[i], &id))
248                                 gr = getgrgid((gid_t)id);
249                         else
250                                 gr = getgrnam(argv[i]);
251                         if (gr != NULL)
252                                 GROUPPRINT;
253                         else {
254                                 rv = RV_NOTFOUND;
255                                 break;
256                         }
257                 }
258         }
259         endgrent();
260         return rv;
261 }
262
263
264 /*
265  * hosts
266  */
267
268 static void
269 hostsprint(const struct hostent *he)
270 {
271         char    buf[INET6_ADDRSTRLEN];
272
273         assert(he != NULL);
274         if (inet_ntop(he->h_addrtype, he->h_addr, buf, sizeof(buf)) == NULL)
275                 strlcpy(buf, "# unknown", sizeof(buf));
276         printfmtstrings(he->h_aliases, "  ", " ", "%-16s  %s", buf, he->h_name);
277 }
278
279 static int
280 hosts(int argc, char *argv[])
281 {
282         struct hostent  *he4, *he6;
283         char            addr[IN6ADDRSZ];
284         int             i, rv;
285
286         assert(argc > 1);
287         assert(argv != NULL);
288
289         sethostent(1);
290         he4 = he6 = NULL;
291         rv = RV_OK;
292         if (argc == 2) {
293                 while ((he4 = gethostent()) != NULL)
294                         hostsprint(he4);
295         } else {
296                 for (i = 2; i < argc; i++) {
297                         if (inet_pton(AF_INET6, argv[i], (void *)addr) > 0) {
298                                 he6 = gethostbyaddr(addr, IN6ADDRSZ, AF_INET6);
299                                 if (he6 != NULL)
300                                         hostsprint(he6);
301                         } else if (inet_pton(AF_INET, argv[i],
302                             (void *)addr) > 0) {
303                                 he4 = gethostbyaddr(addr, INADDRSZ, AF_INET);
304                                 if (he4 != NULL)
305                                         hostsprint(he4);
306                         } else {
307                                 he6 = gethostbyname2(argv[i], AF_INET6);
308                                 if (he6 != NULL)
309                                         hostsprint(he6);
310                                 he4 = gethostbyname(argv[i]);
311                                 if (he4 != NULL)
312                                         hostsprint(he4);
313                         }
314                         if ( he4 == NULL && he6 == NULL ) {
315                                 rv = RV_NOTFOUND;
316                                 break;
317                         }
318                 }
319         }
320         endhostent();
321         return rv;
322 }
323
324 /*
325  * networks
326  */
327 static void
328 networksprint(const struct netent *ne)
329 {
330         char            buf[INET6_ADDRSTRLEN];
331         struct  in_addr ianet;
332
333         assert(ne != NULL);
334         ianet = inet_makeaddr(ne->n_net, 0);
335         if (inet_ntop(ne->n_addrtype, &ianet, buf, sizeof(buf)) == NULL)
336                 strlcpy(buf, "# unknown", sizeof(buf));
337         printfmtstrings(ne->n_aliases, "  ", " ", "%-16s  %s", ne->n_name, buf);
338 }
339
340 static int
341 networks(int argc, char *argv[])
342 {
343         struct netent   *ne;
344         in_addr_t       net;
345         int             i, rv;
346
347         assert(argc > 1);
348         assert(argv != NULL);
349
350         setnetent(1);
351         rv = RV_OK;
352         if (argc == 2) {
353                 while ((ne = getnetent()) != NULL)
354                         networksprint(ne);
355         } else {
356                 for (i = 2; i < argc; i++) {
357                         net = inet_network(argv[i]);
358                         if (net != INADDR_NONE)
359                                 ne = getnetbyaddr(net, AF_INET);
360                         else
361                                 ne = getnetbyname(argv[i]);
362                         if (ne != NULL)
363                                 networksprint(ne);
364                         else {
365                                 rv = RV_NOTFOUND;
366                                 break;
367                         }
368                 }
369         }
370         endnetent();
371         return rv;
372 }
373
374 /*
375  * passwd
376  */
377 static int
378 passwd(int argc, char *argv[])
379 {
380         struct passwd   *pw;
381         unsigned long   id;
382         int             i, rv;
383
384         assert(argc > 1);
385         assert(argv != NULL);
386
387 #define PASSWDPRINT     printf("%s:%s:%u:%u:%s:%s:%s\n", \
388                             pw->pw_name, pw->pw_passwd, pw->pw_uid, \
389                             pw->pw_gid, pw->pw_gecos, pw->pw_dir, pw->pw_shell)
390
391         setpassent(1);
392         rv = RV_OK;
393         if (argc == 2) {
394                 while ((pw = getpwent()) != NULL)
395                         PASSWDPRINT;
396         } else {
397                 for (i = 2; i < argc; i++) {
398                         if (parsenum(argv[i], &id))
399                                 pw = getpwuid((uid_t)id);
400                         else
401                                 pw = getpwnam(argv[i]);
402                         if (pw != NULL)
403                                 PASSWDPRINT;
404                         else {
405                                 rv = RV_NOTFOUND;
406                                 break;
407                         }
408                 }
409         }
410         endpwent();
411         return rv;
412 }
413
414 /*
415  * protocols
416  */
417 static int
418 protocols(int argc, char *argv[])
419 {
420         struct protoent *pe;
421         unsigned long   id;
422         int             i, rv;
423
424         assert(argc > 1);
425         assert(argv != NULL);
426
427 #define PROTOCOLSPRINT  printfmtstrings(pe->p_aliases, "  ", " ", \
428                             "%-16s  %5d", pe->p_name, pe->p_proto)
429
430         setprotoent(1);
431         rv = RV_OK;
432         if (argc == 2) {
433                 while ((pe = getprotoent()) != NULL)
434                         PROTOCOLSPRINT;
435         } else {
436                 for (i = 2; i < argc; i++) {
437                         if (parsenum(argv[i], &id))
438                                 pe = getprotobynumber((int)id);
439                         else
440                                 pe = getprotobyname(argv[i]);
441                         if (pe != NULL)
442                                 PROTOCOLSPRINT;
443                         else {
444                                 rv = RV_NOTFOUND;
445                                 break;
446                         }
447                 }
448         }
449         endprotoent();
450         return rv;
451 }
452
453 /*
454  * rpc
455  */
456 static int
457 rpc(int argc, char *argv[])
458 {
459         struct rpcent   *re;
460         unsigned long   id;
461         int             i, rv;
462
463         assert(argc > 1);
464         assert(argv != NULL);
465
466 #define RPCPRINT        printfmtstrings(re->r_aliases, "  ", " ", \
467                                 "%-16s  %6d", \
468                                 re->r_name, re->r_number)
469
470         setrpcent(1);
471         rv = RV_OK;
472         if (argc == 2) {
473                 while ((re = getrpcent()) != NULL)
474                         RPCPRINT;
475         } else {
476                 for (i = 2; i < argc; i++) {
477                         if (parsenum(argv[i], &id))
478                                 re = getrpcbynumber((int)id);
479                         else
480                                 re = getrpcbyname(argv[i]);
481                         if (re != NULL)
482                                 RPCPRINT;
483                         else {
484                                 rv = RV_NOTFOUND;
485                                 break;
486                         }
487                 }
488         }
489         endrpcent();
490         return rv;
491 }
492
493 /*
494  * services
495  */
496 static int
497 services(int argc, char *argv[])
498 {
499         struct servent  *se;
500         unsigned long   id;
501         char            *proto;
502         int             i, rv;
503
504         assert(argc > 1);
505         assert(argv != NULL);
506
507 #define SERVICESPRINT   printfmtstrings(se->s_aliases, "  ", " ", \
508                             "%-16s  %5d/%s", \
509                             se->s_name, ntohs(se->s_port), se->s_proto)
510
511         setservent(1);
512         rv = RV_OK;
513         if (argc == 2) {
514                 while ((se = getservent()) != NULL)
515                         SERVICESPRINT;
516         } else {
517                 for (i = 2; i < argc; i++) {
518                         proto = strchr(argv[i], '/');
519                         if (proto != NULL)
520                                 *proto++ = '\0';
521                         if (parsenum(argv[i], &id))
522                                 se = getservbyport(htons((u_short)id), proto);
523                         else
524                                 se = getservbyname(argv[i], proto);
525                         if (se != NULL)
526                                 SERVICESPRINT;
527                         else {
528                                 rv = RV_NOTFOUND;
529                                 break;
530                         }
531                 }
532         }
533         endservent();
534         return rv;
535 }
536
537 /*
538  * shells
539  */
540 static int
541 shells(int argc, char *argv[])
542 {
543         const char      *sh;
544         int             i, rv;
545
546         assert(argc > 1);
547         assert(argv != NULL);
548
549 #define SHELLSPRINT     printf("%s\n", sh)
550
551         setusershell();
552         rv = RV_OK;
553         if (argc == 2) {
554                 while ((sh = getusershell()) != NULL)
555                         SHELLSPRINT;
556         } else {
557                 for (i = 2; i < argc; i++) {
558                         setusershell();
559                         while ((sh = getusershell()) != NULL) {
560                                 if (strcmp(sh, argv[i]) == 0) {
561                                         SHELLSPRINT;
562                                         break;
563                                 }
564                         }
565                         if (sh == NULL) {
566                                 rv = RV_NOTFOUND;
567                                 break;
568                         }
569                 }
570         }
571         endusershell();
572         return rv;
573 }
574
575 /*
576  * netgroup
577  */
578 static int
579 netgroup(int argc, char *argv[])
580 {
581         char            *host, *user, *domain;
582         int             first;
583         int             rv, i;
584
585         assert(argc > 1);
586         assert(argv != NULL);
587
588 #define NETGROUPPRINT(s)        (((s) != NULL) ? (s) : "")
589
590         rv = RV_OK;
591         if (argc == 2) {
592                 fprintf(stderr, "Enumeration not supported on netgroup\n");
593                 rv = RV_NOENUM;
594         } else {
595                 for (i = 2; i < argc; i++) {
596                         setnetgrent(argv[i]);
597                         first = 1;
598                         while (getnetgrent(&host, &user, &domain) != 0) {
599                                 if (first) {
600                                         first = 0;
601                                         (void)fputs(argv[i], stdout);
602                                 }
603                                 (void)printf(" (%s,%s,%s)",
604                                     NETGROUPPRINT(host),
605                                     NETGROUPPRINT(user),
606                                     NETGROUPPRINT(domain));
607                         }
608                         if (!first)
609                                 (void)putchar('\n');
610                         endnetgrent();
611                 }
612         }
613         return rv;
614 }
615
616 /*
617  * utmpx
618  */
619
620 #define UTMPXPRINTID do {                       \
621         size_t i;                               \
622         for (i = 0; i < sizeof ut->ut_id; i++)  \
623                 printf("%02hhx", ut->ut_id[i]); \
624 } while (0)
625
626 static void
627 utmpxprint(const struct utmpx *ut)
628 {
629
630         if (ut->ut_type == EMPTY)
631                 return;
632         
633         printf("[%jd.%06u -- %.24s] ",
634             (intmax_t)ut->ut_tv.tv_sec, (unsigned int)ut->ut_tv.tv_usec,
635             ctime(&ut->ut_tv.tv_sec));
636
637         switch (ut->ut_type) {
638         case BOOT_TIME:
639                 printf("system boot\n");
640                 return;
641         case SHUTDOWN_TIME:
642                 printf("system shutdown\n");
643                 return;
644         case OLD_TIME:
645                 printf("old system time\n");
646                 return;
647         case NEW_TIME:
648                 printf("new system time\n");
649                 return;
650         case USER_PROCESS:
651                 printf("user process: id=\"");
652                 UTMPXPRINTID;
653                 printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n",
654                     ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host);
655                 break;
656         case INIT_PROCESS:
657                 printf("init process: id=\"");
658                 UTMPXPRINTID;
659                 printf("\" pid=\"%d\"\n", ut->ut_pid);
660                 break;
661         case LOGIN_PROCESS:
662                 printf("login process: id=\"");
663                 UTMPXPRINTID;
664                 printf("\" pid=\"%d\" user=\"%s\" line=\"%s\" host=\"%s\"\n",
665                     ut->ut_pid, ut->ut_user, ut->ut_line, ut->ut_host);
666                 break;
667         case DEAD_PROCESS:
668                 printf("dead process: id=\"");
669                 UTMPXPRINTID;
670                 printf("\" pid=\"%d\"\n", ut->ut_pid);
671                 break;
672         default:
673                 printf("unknown record type %hu\n", ut->ut_type);
674                 break;
675         }
676 }
677
678 static int
679 utmpx(int argc, char *argv[])
680 {
681         const struct utmpx *ut;
682         const char *file = NULL;
683         int rv = RV_OK, db = 0;
684
685         assert(argc > 1);
686         assert(argv != NULL);
687
688         if (argc == 3 || argc == 4) {
689                 if (strcmp(argv[2], "active") == 0)
690                         db = UTXDB_ACTIVE;
691                 else if (strcmp(argv[2], "lastlogin") == 0)
692                         db = UTXDB_LASTLOGIN;
693                 else if (strcmp(argv[2], "log") == 0)
694                         db = UTXDB_LOG;
695                 else
696                         rv = RV_USAGE;
697                 if (argc == 4)
698                         file = argv[3];
699         } else {
700                 rv = RV_USAGE;
701         }
702
703         if (rv == RV_USAGE) {
704                 fprintf(stderr,
705                     "Usage: %s utmpx active | lastlogin | log [filename]\n",
706                     getprogname());
707         } else if (rv == RV_OK) {
708                 if (setutxdb(db, file) != 0)
709                         return (RV_NOTFOUND);
710                 while ((ut = getutxent()) != NULL)
711                         utmpxprint(ut);
712                 endutxent();
713         }
714         return (rv);
715 }