Speed up x86-64 strcasestr a bit moew.
[glibc.git] / nss / getent.c
blobf6c0b5d434dbfbd9ed6de84f05e2db6af4f57a41
1 /* Copyright (c) 1998-2008, 2009, 2010 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
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.
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.
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. */
20 /* getent: get entries from administrative database. */
22 #include <aliases.h>
23 #include <argp.h>
24 #include <ctype.h>
25 #include <error.h>
26 #include <grp.h>
27 #include <gshadow.h>
28 #include <libintl.h>
29 #include <locale.h>
30 #include <mcheck.h>
31 #include <netdb.h>
32 #include <pwd.h>
33 #include <shadow.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <arpa/inet.h>
39 #include <arpa/nameser.h>
40 #include <netinet/ether.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
44 /* Get libc version number. */
45 #include <version.h>
47 #define PACKAGE _libc_intl_domainname
49 /* Name and version of program. */
50 static void print_version (FILE *stream, struct argp_state *state);
51 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
53 /* Short description of parameters. */
54 static const char args_doc[] = N_("database [key ...]");
56 /* Supported options. */
57 static const struct argp_option args_options[] =
59 { "service", 's', "CONFIG", 0, N_("Service configuration to be used") },
60 { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
61 { NULL, 0, NULL, 0, NULL },
64 /* Short description of program. */
65 static const char doc[] = N_("Get entries from administrative database.");
67 /* Prototype for option handler. */
68 static error_t parse_option (int key, char *arg, struct argp_state *state);
70 /* Function to print some extra text in the help message. */
71 static char *more_help (int key, const char *text, void *input);
73 /* Data structure to communicate with argp functions. */
74 static struct argp argp =
76 args_options, parse_option, args_doc, doc, NULL, more_help
79 /* Additional getaddrinfo flags for IDN encoding. */
80 static int idn_flags = AI_IDN | AI_CANONIDN;
82 /* Print the version information. */
83 static void
84 print_version (FILE *stream, struct argp_state *state)
86 fprintf (stream, "getent (GNU %s) %s\n", PACKAGE, VERSION);
87 fprintf (stream, gettext ("\
88 Copyright (C) %s Free Software Foundation, Inc.\n\
89 This is free software; see the source for copying conditions. There is NO\n\
90 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
91 "), "2010");
92 fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
95 /* This is for aliases */
96 static inline void
97 print_aliases (struct aliasent *alias)
99 unsigned int i = 0;
101 printf ("%s: ", alias->alias_name);
102 for (i = strlen (alias->alias_name); i < 14; ++i)
103 fputs_unlocked (" ", stdout);
105 for (i = 0; i < alias->alias_members_len; ++i)
106 printf ("%s%s",
107 alias->alias_members [i],
108 i + 1 == alias->alias_members_len ? "\n" : ", ");
111 static int
112 aliases_keys (int number, char *key[])
114 int result = 0;
115 int i;
116 struct aliasent *alias;
118 if (number == 0)
120 setaliasent ();
121 while ((alias = getaliasent ()) != NULL)
122 print_aliases (alias);
123 endaliasent ();
124 return result;
127 for (i = 0; i < number; ++i)
129 alias = getaliasbyname (key[i]);
131 if (alias == NULL)
132 result = 2;
133 else
134 print_aliases (alias);
137 return result;
140 /* This is for ethers */
141 static int
142 ethers_keys (int number, char *key[])
144 int result = 0;
145 int i;
147 if (number == 0)
149 fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
150 return 3;
153 for (i = 0; i < number; ++i)
155 struct ether_addr *ethp, eth;
156 char buffer [1024], *p;
158 ethp = ether_aton (key[i]);
159 if (ethp != NULL)
161 if (ether_ntohost (buffer, ethp))
163 result = 2;
164 continue;
166 p = buffer;
168 else
170 if (ether_hostton (key[i], &eth))
172 result = 2;
173 continue;
175 p = key[i];
176 ethp = &eth;
178 printf ("%s %s\n", ether_ntoa (ethp), p);
181 return result;
184 /* This is for group */
185 static inline void
186 print_group (struct group *grp)
188 unsigned int i = 0;
190 printf ("%s:%s:%lu:", grp->gr_name ? grp->gr_name : "",
191 grp->gr_passwd ? grp->gr_passwd : "",
192 (unsigned long int) grp->gr_gid);
194 while (grp->gr_mem[i] != NULL)
196 fputs_unlocked (grp->gr_mem[i], stdout);
197 ++i;
198 if (grp->gr_mem[i] != NULL)
199 putchar_unlocked (',');
201 putchar_unlocked ('\n');
204 static int
205 group_keys (int number, char *key[])
207 int result = 0;
208 int i;
209 struct group *grp;
211 if (number == 0)
213 setgrent ();
214 while ((grp = getgrent ()) != NULL)
215 print_group (grp);
216 endgrent ();
217 return result;
220 for (i = 0; i < number; ++i)
222 errno = 0;
223 char *ep;
224 gid_t arg_gid = strtoul(key[i], &ep, 10);
226 if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
227 /* Valid numeric gid. */
228 grp = getgrgid (arg_gid);
229 else
230 grp = getgrnam (key[i]);
232 if (grp == NULL)
233 result = 2;
234 else
235 print_group (grp);
238 return result;
241 /* This is for gshadow */
242 static void
243 print_gshadow (struct sgrp *sg)
245 unsigned int i = 0;
247 printf ("%s:%s:",
248 sg->sg_namp ? sg->sg_namp : "",
249 sg->sg_passwd ? sg->sg_passwd : "");
251 while (sg->sg_adm[i] != NULL)
253 fputs_unlocked (sg->sg_adm[i], stdout);
254 ++i;
255 if (sg->sg_adm[i] != NULL)
256 putchar_unlocked (',');
259 putchar_unlocked (':');
261 i = 0;
262 while (sg->sg_mem[i] != NULL)
264 fputs_unlocked (sg->sg_mem[i], stdout);
265 ++i;
266 if (sg->sg_mem[i] != NULL)
267 putchar_unlocked (',');
270 putchar_unlocked ('\n');
273 static int
274 gshadow_keys (int number, char *key[])
276 int result = 0;
277 int i;
279 if (number == 0)
281 struct sgrp *sg;
283 setsgent ();
284 while ((sg = getsgent ()) != NULL)
285 print_gshadow (sg);
286 endsgent ();
287 return result;
290 for (i = 0; i < number; ++i)
292 struct sgrp *sg;
294 sg = getsgnam (key[i]);
296 if (sg == NULL)
297 result = 2;
298 else
299 print_gshadow (sg);
302 return result;
305 /* This is for hosts */
306 static void
307 print_hosts (struct hostent *host)
309 unsigned int cnt;
311 for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
313 char buf[INET6_ADDRSTRLEN];
314 const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
315 buf, sizeof (buf));
317 printf ("%-15s %s", ip, host->h_name);
319 unsigned int i;
320 for (i = 0; host->h_aliases[i] != NULL; ++i)
322 putchar_unlocked (' ');
323 fputs_unlocked (host->h_aliases[i], stdout);
325 putchar_unlocked ('\n');
329 static int
330 hosts_keys (int number, char *key[])
332 int result = 0;
333 int i;
334 struct hostent *host;
336 if (number == 0)
338 sethostent (0);
339 while ((host = gethostent ()) != NULL)
340 print_hosts (host);
341 endhostent ();
342 return result;
345 for (i = 0; i < number; ++i)
347 struct hostent *host = NULL;
348 char addr[IN6ADDRSZ];
350 if (inet_pton (AF_INET6, key[i], &addr) > 0)
351 host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
352 else if (inet_pton (AF_INET, key[i], &addr) > 0)
353 host = gethostbyaddr (addr, INADDRSZ, AF_INET);
354 else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
355 host = gethostbyname2 (key[i], AF_INET);
357 if (host == NULL)
358 result = 2;
359 else
360 print_hosts (host);
363 return result;
366 /* This is for hosts, but using getaddrinfo */
367 static int
368 ahosts_keys_int (int af, int xflags, int number, char *key[])
370 int result = 0;
371 int i;
372 struct hostent *host;
374 if (number == 0)
376 sethostent (0);
377 while ((host = gethostent ()) != NULL)
378 print_hosts (host);
379 endhostent ();
380 return result;
383 struct addrinfo hint;
384 memset (&hint, '\0', sizeof (hint));
385 hint.ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME
386 | idn_flags | xflags);
387 hint.ai_family = af;
389 for (i = 0; i < number; ++i)
391 struct addrinfo *res;
393 if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
394 result = 2;
395 else
397 struct addrinfo *runp = res;
399 while (runp != NULL)
401 char sockbuf[20];
402 const char *sockstr;
403 if (runp->ai_socktype == SOCK_STREAM)
404 sockstr = "STREAM";
405 else if (runp->ai_socktype == SOCK_DGRAM)
406 sockstr = "DGRAM";
407 else if (runp->ai_socktype == SOCK_RAW)
408 sockstr = "RAW";
409 #ifdef SOCK_SEQPACKET
410 else if (runp->ai_socktype == SOCK_SEQPACKET)
411 sockstr = "SEQPACKET";
412 #endif
413 #ifdef SOCK_RDM
414 else if (runp->ai_socktype == SOCK_RDM)
415 sockstr = "RDM";
416 #endif
417 #ifdef SOCK_DCCP
418 else if (runp->ai_socktype == SOCK_DCCP)
419 sockstr = "DCCP";
420 #endif
421 #ifdef SOCK_PACKET
422 else if (runp->ai_socktype == SOCK_PACKET)
423 sockstr = "PACKET";
424 #endif
425 else
427 snprintf (sockbuf, sizeof (sockbuf), "%d",
428 runp->ai_socktype);
429 sockstr = sockbuf;
432 char buf[INET6_ADDRSTRLEN];
433 printf ("%-15s %-6s %s\n",
434 inet_ntop (runp->ai_family,
435 runp->ai_family == AF_INET
436 ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
437 : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr,
438 buf, sizeof (buf)),
439 sockstr,
440 runp->ai_canonname ?: "");
442 runp = runp->ai_next;
445 freeaddrinfo (res);
449 return result;
452 static int
453 ahosts_keys (int number, char *key[])
455 return ahosts_keys_int (AF_UNSPEC, 0, number, key);
458 static int
459 ahostsv4_keys (int number, char *key[])
461 return ahosts_keys_int (AF_INET, 0, number, key);
464 static int
465 ahostsv6_keys (int number, char *key[])
467 return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key);
470 /* This is for netgroup */
471 static int
472 netgroup_keys (int number, char *key[])
474 int result = 0;
475 int i;
477 if (number == 0)
479 fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
480 return 3;
483 for (i = 0; i < number; ++i)
485 if (!setnetgrent (key[i]))
486 result = 2;
487 else
489 char *p[3];
491 printf ("%-21s", key[i]);
493 while (getnetgrent (p, p + 1, p + 2))
494 printf (" (%s, %s, %s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
495 putchar_unlocked ('\n');
499 endnetgrent ();
501 return result;
504 /* This is for networks */
505 static void
506 print_networks (struct netent *net)
508 unsigned int i;
509 struct in_addr ip;
510 ip.s_addr = htonl (net->n_net);
512 printf ("%-21s %s", net->n_name, inet_ntoa (ip));
514 i = 0;
515 while (net->n_aliases[i] != NULL)
517 putchar_unlocked (' ');
518 fputs_unlocked (net->n_aliases[i], stdout);
519 ++i;
521 putchar_unlocked ('\n');
524 static int
525 networks_keys (int number, char *key[])
527 int result = 0;
528 int i;
529 struct netent *net;
531 if (number == 0)
533 setnetent (0);
534 while ((net = getnetent ()) != NULL)
535 print_networks (net);
536 endnetent ();
537 return result;
540 for (i = 0; i < number; ++i)
542 if (isdigit (key[i][0]))
543 net = getnetbyaddr (ntohl (inet_addr (key[i])), AF_UNSPEC);
544 else
545 net = getnetbyname (key[i]);
547 if (net == NULL)
548 result = 2;
549 else
550 print_networks (net);
553 return result;
556 /* Now is all for passwd */
557 static inline void
558 print_passwd (struct passwd *pwd)
560 printf ("%s:%s:%lu:%lu:%s:%s:%s\n",
561 pwd->pw_name ? pwd->pw_name : "",
562 pwd->pw_passwd ? pwd->pw_passwd : "",
563 (unsigned long int) pwd->pw_uid,
564 (unsigned long int) pwd->pw_gid,
565 pwd->pw_gecos ? pwd->pw_gecos : "",
566 pwd->pw_dir ? pwd->pw_dir : "",
567 pwd->pw_shell ? pwd->pw_shell : "");
570 static int
571 passwd_keys (int number, char *key[])
573 int result = 0;
574 int i;
575 struct passwd *pwd;
577 if (number == 0)
579 setpwent ();
580 while ((pwd = getpwent ()) != NULL)
581 print_passwd (pwd);
582 endpwent ();
583 return result;
586 for (i = 0; i < number; ++i)
588 errno = 0;
589 char *ep;
590 uid_t arg_uid = strtoul(key[i], &ep, 10);
592 if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
593 /* Valid numeric uid. */
594 pwd = getpwuid (arg_uid);
595 else
596 pwd = getpwnam (key[i]);
598 if (pwd == NULL)
599 result = 2;
600 else
601 print_passwd (pwd);
604 return result;
607 /* This is for protocols */
608 static inline void
609 print_protocols (struct protoent *proto)
611 unsigned int i;
613 printf ("%-21s %d", proto->p_name, proto->p_proto);
615 i = 0;
616 while (proto->p_aliases[i] != NULL)
618 putchar_unlocked (' ');
619 fputs_unlocked (proto->p_aliases[i], stdout);
620 ++i;
622 putchar_unlocked ('\n');
625 static int
626 protocols_keys (int number, char *key[])
628 int result = 0;
629 int i;
630 struct protoent *proto;
632 if (number == 0)
634 setprotoent (0);
635 while ((proto = getprotoent ()) != NULL)
636 print_protocols (proto);
637 endprotoent ();
638 return result;
641 for (i = 0; i < number; ++i)
643 if (isdigit (key[i][0]))
644 proto = getprotobynumber (atol (key[i]));
645 else
646 proto = getprotobyname (key[i]);
648 if (proto == NULL)
649 result = 2;
650 else
651 print_protocols (proto);
654 return result;
657 /* Now is all for rpc */
658 static inline void
659 print_rpc (struct rpcent *rpc)
661 int i;
663 printf ("%-15s %d%s",
664 rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
666 for (i = 0; rpc->r_aliases[i]; ++i)
667 printf (" %s", rpc->r_aliases[i]);
668 putchar_unlocked ('\n');
671 static int
672 rpc_keys (int number, char *key[])
674 int result = 0;
675 int i;
676 struct rpcent *rpc;
678 if (number == 0)
680 setrpcent (0);
681 while ((rpc = getrpcent ()) != NULL)
682 print_rpc (rpc);
683 endrpcent ();
684 return result;
687 for (i = 0; i < number; ++i)
689 if (isdigit (key[i][0]))
690 rpc = getrpcbynumber (atol (key[i]));
691 else
692 rpc = getrpcbyname (key[i]);
694 if (rpc == NULL)
695 result = 2;
696 else
697 print_rpc (rpc);
700 return result;
703 /* for services */
704 static void
705 print_services (struct servent *serv)
707 unsigned int i;
709 printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
711 i = 0;
712 while (serv->s_aliases[i] != NULL)
714 putchar_unlocked (' ');
715 fputs_unlocked (serv->s_aliases[i], stdout);
716 ++i;
718 putchar_unlocked ('\n');
721 static int
722 services_keys (int number, char *key[])
724 int result = 0;
725 int i;
726 struct servent *serv;
728 if (!number)
730 setservent (0);
731 while ((serv = getservent ()) != NULL)
732 print_services (serv);
733 endservent ();
734 return result;
737 for (i = 0; i < number; ++i)
739 struct servent *serv;
740 char *proto = strchr (key[i], '/');
742 if (proto != NULL)
743 *proto++ = '\0';
745 if (isdigit (key[i][0]))
746 serv = getservbyport (htons (atol (key[i])), proto);
747 else
748 serv = getservbyname (key[i], proto);
750 if (serv == NULL)
751 result = 2;
752 else
753 print_services (serv);
756 return result;
759 /* This is for shadow */
760 static void
761 print_shadow (struct spwd *sp)
763 printf ("%s:%s:",
764 sp->sp_namp ? sp->sp_namp : "",
765 sp->sp_pwdp ? sp->sp_pwdp : "");
767 #define SHADOW_FIELD(n) \
768 if (sp->n == -1) \
769 putchar_unlocked (':'); \
770 else \
771 printf ("%ld:", sp->n)
773 SHADOW_FIELD (sp_lstchg);
774 SHADOW_FIELD (sp_min);
775 SHADOW_FIELD (sp_max);
776 SHADOW_FIELD (sp_warn);
777 SHADOW_FIELD (sp_inact);
778 SHADOW_FIELD (sp_expire);
779 if (sp->sp_flag == ~0ul)
780 putchar_unlocked ('\n');
781 else
782 printf ("%lu\n", sp->sp_flag);
785 static int
786 shadow_keys (int number, char *key[])
788 int result = 0;
789 int i;
791 if (number == 0)
793 struct spwd *sp;
795 setspent ();
796 while ((sp = getspent ()) != NULL)
797 print_shadow (sp);
798 endpwent ();
799 return result;
802 for (i = 0; i < number; ++i)
804 struct spwd *sp;
806 sp = getspnam (key[i]);
808 if (sp == NULL)
809 result = 2;
810 else
811 print_shadow (sp);
814 return result;
817 struct
819 const char *name;
820 int (*func) (int number, char *key[]);
821 } databases[] =
823 #define D(name) { #name, name ## _keys },
824 D(ahosts)
825 D(ahostsv4)
826 D(ahostsv6)
827 D(aliases)
828 D(ethers)
829 D(group)
830 D(gshadow)
831 D(hosts)
832 D(netgroup)
833 D(networks)
834 D(passwd)
835 D(protocols)
836 D(rpc)
837 D(services)
838 D(shadow)
839 #undef D
840 { NULL, NULL }
843 /* Handle arguments found by argp. */
844 static error_t
845 parse_option (int key, char *arg, struct argp_state *state)
847 char *endp;
848 switch (key)
850 case 's':
851 endp = strchr (arg, ':');
852 if (endp == NULL)
853 /* No specific database, change them all. */
854 for (int i = 0; databases[i].name != NULL; ++i)
855 __nss_configure_lookup (databases[i].name, arg);
856 else
858 int i;
859 for (i = 0; databases[i].name != NULL; ++i)
860 if (strncmp (databases[i].name, arg, endp - arg) == 0)
862 __nss_configure_lookup (databases[i].name, endp + 1);
863 break;
865 if (databases[i].name == NULL)
866 error (EXIT_FAILURE, 0, gettext ("Unknown database name"));
868 break;
870 case 'i':
871 idn_flags = 0;
872 break;
874 default:
875 return ARGP_ERR_UNKNOWN;
878 return 0;
882 static char *
883 more_help (int key, const char *text, void *input)
885 switch (key)
887 size_t len;
888 char *doc;
889 FILE *fp;
891 case ARGP_KEY_HELP_EXTRA:
892 /* We print some extra information. */
893 fp = open_memstream (&doc, &len);
894 if (fp != NULL)
896 fputs_unlocked (_("Supported databases:\n"), fp);
898 for (int i = 0, col = 0; databases[i].name != NULL; ++i)
900 len = strlen (databases[i].name);
901 if (i != 0)
903 if (col + len > 72)
905 col = 0;
906 fputc_unlocked ('\n', fp);
908 else
909 fputc_unlocked (' ', fp);
912 fputs_unlocked (databases[i].name, fp);
913 col += len + 1;
916 fputs ("\n\n", fp);
918 fputs (gettext ("\
919 For bug reporting instructions, please see:\n\
920 <http://www.gnu.org/software/libc/bugs.html>.\n"), fp);
922 if (fclose (fp) == 0)
923 return doc;
925 break;
927 default:
928 break;
930 return (char *) text;
934 /* the main function */
936 main (int argc, char *argv[])
938 /* Debugging support. */
939 mtrace ();
941 /* Set locale via LC_ALL. */
942 setlocale (LC_ALL, "");
943 /* Set the text message domain. */
944 textdomain (PACKAGE);
946 /* Parse and process arguments. */
947 int remaining;
948 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
950 if ((argc - remaining) < 1)
952 error (0, 0, gettext ("wrong number of arguments"));
953 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
954 return 1;
957 for (int i = 0; databases[i].name; ++i)
958 if (argv[remaining][0] == databases[i].name[0]
959 && !strcmp (argv[remaining], databases[i].name))
960 return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
962 fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
963 argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
964 return 1;