Update to LGPL v2.1.
[platform/upstream/glibc.git] / nss / getent.c
1 /* Copyright (c) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 /* getent: get entries from administrative database.  */
21
22 #include <aliases.h>
23 #include <argp.h>
24 #include <grp.h>
25 #include <pwd.h>
26 #include <shadow.h>
27 #include <ctype.h>
28 #include <error.h>
29 #include <libintl.h>
30 #include <locale.h>
31 #include <netdb.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <netinet/ether.h>
38 #include <arpa/inet.h>
39 #include <arpa/nameser.h>
40
41 /* Get libc version number.  */
42 #include <version.h>
43
44 #define PACKAGE _libc_intl_domainname
45
46 /* Name and version of program.  */
47 static void print_version (FILE *stream, struct argp_state *state);
48 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
49
50 /* Short description of parameters.  */
51 static const char args_doc[] = N_("database [key ...]");
52
53 /* Data structure to communicate with argp functions.  */
54 static struct argp argp = {
55   NULL, NULL, args_doc, NULL,
56 };
57
58 /* Print the version information.  */
59 static void
60 print_version (FILE *stream, struct argp_state *state)
61 {
62   fprintf (stream, "getent (GNU %s) %s\n", PACKAGE, VERSION);
63   fprintf (stream, gettext ("\
64 Copyright (C) %s Free Software Foundation, Inc.\n\
65 This is free software; see the source for copying conditions.  There is NO\n\
66 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
67 "), "2001");
68   fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
69 }
70
71 /* This is for aliases */
72 static inline void
73 print_aliases (struct aliasent *alias)
74 {
75   unsigned int i = 0;
76
77   printf ("%s: ", alias->alias_name);
78   for  (i = strlen (alias->alias_name); i < 14; ++i)
79     fputs (" ", stdout);
80
81   for (i = 0;
82        i < alias->alias_members_len;
83        ++i)
84     printf ("%s%s",
85             alias->alias_members [i],
86             i + 1 == alias->alias_members_len ? "\n" : ", ");
87 }
88
89 static int
90 aliases_keys (int number, char *key[])
91 {
92   int result = 0;
93   int i;
94   struct aliasent *alias;
95
96   if (!number)
97     {
98       setaliasent ();
99       while ((alias = getaliasent()) != NULL)
100         print_aliases (alias);
101       endaliasent ();
102       return result;
103     }
104
105   for (i = 0; i < number; ++i)
106     {
107       alias = getaliasbyname (key[i]);
108
109       if (alias == NULL)
110         result = 2;
111       else
112         print_aliases (alias);
113     }
114
115   return result;
116 }
117
118 /* This is for ethers */
119 static int
120 ethers_keys (int number, char *key[])
121 {
122   int result = 0;
123   int i;
124
125   if (!number)
126     {
127       fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
128       return 3;
129     }
130
131   for (i = 0; i < number; ++i)
132     {
133       struct ether_addr *ethp, eth;
134       char buffer [1024], *p;
135
136       ethp = ether_aton (key[i]);
137       if (ethp)
138         {
139           if (ether_ntohost (buffer, ethp))
140             {
141               result = 2;
142               continue;
143             }
144           p = buffer;
145         }
146       else
147         {
148           if (ether_hostton (key[i], &eth))
149             {
150               result = 2;
151               continue;
152             }
153           p = key[i];
154           ethp = &eth;
155         }
156       printf ("%s %s\n", ether_ntoa (ethp), p);
157     }
158
159   return result;
160 }
161
162 /* This is for group */
163 static inline void
164 print_group (struct group *grp)
165 {
166   unsigned int i = 0;
167
168   printf ("%s:%s:%ld:", grp->gr_name ? grp->gr_name : "",
169           grp->gr_passwd ? grp->gr_passwd : "",
170           (unsigned long)grp->gr_gid);
171
172   while (grp->gr_mem[i] != NULL)
173     {
174       fputs (grp->gr_mem[i], stdout);
175       ++i;
176       if (grp->gr_mem[i] != NULL)
177         fputs (",", stdout);
178     }
179   fputs ("\n", stdout);
180 }
181
182 static int
183 group_keys (int number, char *key[])
184 {
185   int result = 0;
186   int i;
187   struct group *grp;
188
189   if (!number)
190     {
191       setgrent ();
192       while ((grp = getgrent()) != NULL)
193         print_group (grp);
194       endgrent ();
195       return result;
196     }
197
198   for (i = 0; i < number; ++i)
199     {
200       if (isdigit (key[i][0]))
201         grp = getgrgid (atol (key[i]));
202       else
203         grp = getgrnam (key[i]);
204
205       if (grp == NULL)
206         result = 2;
207       else
208         print_group (grp);
209     }
210
211   return result;
212 }
213
214 /* This is for hosts */
215 static inline void
216 print_hosts (struct hostent *host)
217 {
218   unsigned int i;
219   char buf[INET6_ADDRSTRLEN];
220   const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[0],
221                               buf, sizeof (buf));
222
223   fputs (ip, stdout);
224   for (i = strlen (ip); i < 15; ++i)
225     fputs (" ", stdout);
226   fputs (" ", stdout);
227   fputs (host->h_name, stdout);
228
229   i = 0;
230   while (host->h_aliases[i] != NULL)
231     {
232       fputs (" ", stdout);
233       fputs (host->h_aliases[i], stdout);
234       ++i;
235     }
236   fputs ("\n", stdout);
237 }
238
239 static int
240 hosts_keys (int number, char *key[])
241 {
242   int result = 0;
243   int i;
244   struct hostent *host;
245
246   if (!number)
247     {
248       sethostent (0);
249       while ((host = gethostent()) != NULL)
250         print_hosts (host);
251       endhostent ();
252       return result;
253     }
254
255   for (i = 0; i < number; ++i)
256     {
257       struct hostent *host = NULL;
258
259       if (strchr (key[i], ':') != NULL)
260         {
261           char addr[IN6ADDRSZ];
262           if (inet_pton (AF_INET6, key[i], &addr))
263             host = gethostbyaddr (addr, sizeof (addr), AF_INET6);
264         }
265       else if (isdigit (key[i][0]))
266         {
267           char addr[INADDRSZ];
268           if (inet_pton (AF_INET, key[i], &addr))
269             host = gethostbyaddr (addr, sizeof (addr), AF_INET);
270         }
271       else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
272         host = gethostbyname2 (key[i], AF_INET);
273
274       if (host == NULL)
275         result = 2;
276       else
277         print_hosts (host);
278     }
279
280   return result;
281 }
282
283 /* This is for netgroup */
284 static int
285 netgroup_keys (int number, char *key[])
286 {
287   int result = 0;
288   int i, j;
289
290   if (!number)
291     {
292       fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
293       return 3;
294     }
295
296   for (i = 0; i < number; ++i)
297     {
298       if (!setnetgrent (key[i]))
299         result = 2;
300       else
301         {
302           char *p[3];
303
304           fputs (key[i], stdout);
305           for (j = strlen (key[i]); j < 21; ++j)
306             fputs (" ", stdout);
307
308           while (getnetgrent (p, p + 1, p + 2))
309             printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
310           fputs ("\n", stdout);
311         }
312     }
313
314   return result;
315 }
316
317 /* This is for networks */
318 static inline void
319 print_networks (struct netent *net)
320 {
321   unsigned int i;
322   struct in_addr ip;
323   ip.s_addr = htonl (net->n_net);
324
325   printf ("%s ", net->n_name);
326   for  (i = strlen (net->n_name); i < 21; ++i)
327     fputs (" ", stdout);
328   fputs (inet_ntoa (ip), stdout);
329
330   i = 0;
331   while (net->n_aliases[i] != NULL)
332     {
333       fputs (" ", stdout);
334       fputs (net->n_aliases[i], stdout);
335       ++i;
336       if (net->n_aliases[i] != NULL)
337         fputs (",", stdout);
338     }
339   fputs ("\n", stdout);
340 }
341
342 static int
343 networks_keys (int number, char *key[])
344 {
345   int result = 0;
346   int i;
347   struct netent *net;
348
349   if (!number)
350     {
351       setnetent (0);
352       while ((net = getnetent()) != NULL)
353         print_networks (net);
354       endnetent ();
355       return result;
356     }
357
358   for (i = 0; i < number; ++i)
359     {
360       if (isdigit (key[i][0]))
361         net = getnetbyaddr (inet_addr (key[i]), AF_UNIX);
362       else
363         net = getnetbyname (key[i]);
364
365       if (net == NULL)
366         result = 2;
367       else
368         print_networks (net);
369     }
370
371   return result;
372 }
373
374 /* Now is all for passwd */
375 static inline void
376 print_passwd (struct passwd *pwd)
377 {
378   printf ("%s:%s:%ld:%ld:%s:%s:%s\n",
379           pwd->pw_name ? pwd->pw_name : "",
380           pwd->pw_passwd ? pwd->pw_passwd : "",
381           (unsigned long)pwd->pw_uid,
382           (unsigned long)pwd->pw_gid,
383           pwd->pw_gecos ? pwd->pw_gecos : "",
384           pwd->pw_dir ? pwd->pw_dir : "",
385           pwd->pw_shell ? pwd->pw_shell : "");
386 }
387
388 static int
389 passwd_keys (int number, char *key[])
390 {
391   int result = 0;
392   int i;
393   struct passwd *pwd;
394
395   if (!number)
396     {
397       setpwent ();
398       while ((pwd = getpwent()) != NULL)
399         print_passwd (pwd);
400       endpwent ();
401       return result;
402     }
403
404   for (i = 0; i < number; ++i)
405     {
406       if (isdigit (key[i][0]))
407         pwd = getpwuid (atol (key[i]));
408       else
409         pwd = getpwnam (key[i]);
410
411       if (pwd == NULL)
412         result = 2;
413       else
414         print_passwd (pwd);
415     }
416
417   return result;
418 }
419
420 /* This is for protocols */
421 static inline void
422 print_protocols (struct protoent *proto)
423 {
424   unsigned int i;
425
426   fputs (proto->p_name, stdout);
427   for (i = strlen (proto->p_name); i < 21; ++i)
428     fputs (" ", stdout);
429   printf (" %d", proto->p_proto);
430
431   i = 0;
432   while (proto->p_aliases[i] != NULL)
433     {
434       fputs (" ", stdout);
435       fputs (proto->p_aliases[i], stdout);
436       ++i;
437     }
438   fputs ("\n", stdout);
439 }
440
441 static int
442 protocols_keys (int number, char *key[])
443 {
444   int result = 0;
445   int i;
446   struct protoent *proto;
447
448   if (!number)
449     {
450       setprotoent (0);
451       while ((proto = getprotoent()) != NULL)
452         print_protocols (proto);
453       endprotoent ();
454       return result;
455     }
456
457   for (i = 0; i < number; ++i)
458     {
459       if (isdigit (key[i][0]))
460         proto = getprotobynumber (atol (key[i]));
461       else
462         proto = getprotobyname (key[i]);
463
464       if (proto == NULL)
465         result = 2;
466       else
467         print_protocols (proto);
468     }
469
470   return result;
471 }
472
473 /* Now is all for rpc */
474 static inline void
475 print_rpc (struct rpcent *rpc)
476 {
477   int i;
478
479   fputs (rpc->r_name, stdout);
480   for  (i = strlen (rpc->r_name); i < 15; ++i)
481     fputs (" ", stdout);
482   printf (" %d%s", rpc->r_number, rpc->r_aliases[0] ? " " : "");
483
484   for (i = 0; rpc->r_aliases[i]; ++i)
485     printf (" %s", rpc->r_aliases[i]);
486   fputs ("\n", stdout);
487 }
488
489 static int
490 rpc_keys (int number, char *key[])
491 {
492   int result = 0;
493   int i;
494   struct rpcent *rpc;
495
496   if (!number)
497     {
498       setrpcent (0);
499       while ((rpc = getrpcent()) != NULL)
500         print_rpc (rpc);
501       endrpcent ();
502       return result;
503     }
504
505   for (i = 0; i < number; ++i)
506     {
507       if (isdigit (key[i][0]))
508         rpc = getrpcbynumber (atol (key[i]));
509       else
510         rpc = getrpcbyname (key[i]);
511
512       if (rpc == NULL)
513         result = 2;
514       else
515         print_rpc (rpc);
516     }
517
518   return result;
519 }
520
521 /* for services */
522 static void
523 print_services (struct servent *serv)
524 {
525   unsigned int i;
526
527   fputs (serv->s_name, stdout);
528   for (i = strlen (serv->s_name); i < 21; ++i)
529     fputs (" ", stdout);
530   printf (" %d/%s", ntohs (serv->s_port), serv->s_proto);
531
532   i = 0;
533   while (serv->s_aliases[i] != NULL)
534     {
535       fputs (" ", stdout);
536       fputs (serv->s_aliases[i], stdout);
537       ++i;
538     }
539   fputs ("\n", stdout);
540 }
541
542 static int
543 services_keys (int number, char *key[])
544 {
545   int result = 0;
546   int i;
547   struct servent *serv;
548
549   if (!number)
550     {
551       setservent (0);
552       while ((serv = getservent()) != NULL)
553         print_services (serv);
554       endservent ();
555       return result;
556     }
557
558   for (i = 0; i < number; ++i)
559     {
560       struct servent *serv;
561       char *proto = strchr (key[i], '/');
562
563       if (proto == NULL)
564         {
565           setservent (0);
566           if (isdigit (key[i][0]))
567             {
568               int port = htons (atol (key[i]));
569               while ((serv = getservent ()) != NULL)
570                 if (serv->s_port == port)
571                   {
572                     print_services (serv);
573                     break;
574                   }
575             }
576           else
577             {
578               int j;
579
580               while ((serv = getservent ()) != NULL)
581                 if (strcmp (serv->s_name, key[i]) == 0)
582                   {
583                     print_services (serv);
584                     break;
585                   }
586                 else
587                   for (j = 0; serv->s_aliases[j]; ++j)
588                     if (strcmp (serv->s_aliases[j], key[i]) == 0)
589                       {
590                         print_services (serv);
591                         break;
592                       }
593             }
594           endservent ();
595         }
596       else
597         {
598           *proto++ = '\0';
599
600           if (isdigit (key[i][0]))
601             serv = getservbyport (htons (atol (key[i])), proto);
602           else
603             serv = getservbyname (key[i], proto);
604
605           if (serv == NULL)
606             result = 2;
607           else
608             print_services (serv);
609         }
610     }
611
612   return result;
613 }
614
615 /* This is for shadow */
616 static inline void
617 print_shadow (struct spwd *sp)
618 {
619   printf ("%s:%s:",
620           sp->sp_namp ? sp->sp_namp : "",
621           sp->sp_pwdp ? sp->sp_pwdp : "");
622
623 #define SHADOW_FIELD(n)         \
624   if (sp->n == -1)              \
625     fputs (":", stdout);        \
626   else                          \
627     printf ("%ld:", sp->n)
628
629   SHADOW_FIELD (sp_lstchg);
630   SHADOW_FIELD (sp_min);
631   SHADOW_FIELD (sp_max);
632   SHADOW_FIELD (sp_warn);
633   SHADOW_FIELD (sp_inact);
634   SHADOW_FIELD (sp_expire);
635   if (sp->sp_flag == ~0ul)
636     fputs ("\n", stdout);
637   else
638     printf ("%lu\n", sp->sp_flag);
639 }
640
641 static int
642 shadow_keys (int number, char *key[])
643 {
644   int result = 0;
645   int i;
646
647   if (!number)
648     {
649       struct spwd *sp;
650
651       setspent ();
652       while ((sp = getspent()) != NULL)
653         print_shadow (sp);
654       endpwent ();
655       return result;
656     }
657
658   for (i = 0; i < number; ++i)
659     {
660       struct spwd *sp;
661
662       sp = getspnam (key[i]);
663
664       if (sp == NULL)
665         result = 2;
666       else
667         print_shadow (sp);
668     }
669
670   return result;
671 }
672
673 struct
674   {
675     const char *name;
676     int (*func) (int number, char *key[]);
677   } databases[] =
678   {
679 #define D(name) { #name, name ## _keys },
680 D(aliases)
681 D(ethers)
682 D(group)
683 D(hosts)
684 D(netgroup)
685 D(networks)
686 D(passwd)
687 D(protocols)
688 D(rpc)
689 D(services)
690 D(shadow)
691 #undef D
692     { NULL, NULL }  
693   };
694
695 /* build doc */
696 static inline void
697 build_doc (void)
698 {
699   int i, j, len;
700   char *short_doc, *long_doc, *doc, *p;
701
702   short_doc = _("getent - get entries from administrative database.");
703   long_doc = _("Supported databases:");
704   len = strlen (short_doc) + strlen (long_doc) + 3;
705
706   for (i = 0; databases[i].name; ++i)
707     len += strlen (databases[i].name) + 1;
708
709   doc = (char *) malloc (len);
710   if (!doc)
711     doc = short_doc;
712   else
713     {
714       p = stpcpy (doc, short_doc);
715       *p++ = '\v';
716       p = stpcpy (p, long_doc);
717       *p++ = '\n';
718
719       for (i = 0, j = 0; databases[i].name; ++i)
720         {
721           len = strlen (databases[i].name);
722           if (i)
723             {
724               if (j + len > 60)
725                 {
726                   j = 0;
727                   *p++ = '\n';
728                 }
729               else
730                 *p++ = ' ';
731             }
732
733           memcpy (p, databases[i].name, len);
734           p += len;
735           j += len + 1;
736         }
737     }
738
739   argp.doc = doc;
740 }
741
742 /* the main function */
743 int
744 main (int argc, char *argv[])
745 {
746   int remaining, i;
747
748   /* Set locale via LC_ALL.  */
749   setlocale (LC_ALL, "");
750   /* Set the text message domain.  */
751   textdomain (PACKAGE);
752
753   /* Build argp.doc.  */
754   build_doc ();
755
756   /* Parse and process arguments.  */
757   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
758
759   if ((argc - remaining) < 1)
760     {
761       error (0, 0, gettext ("wrong number of arguments"));
762       argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
763       return 1;
764     }
765
766   for (i = 0; databases[i].name; ++i)
767     if (argv[1][0] == databases[i].name[0]
768         && !strcmp (argv[1], databases[i].name))
769       return databases[i].func (argc - 2, &argv[2]);
770
771   fprintf (stderr, _("Unknown database: %s\n"), argv[1]);
772   argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
773   return 1;
774 }