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