(root)/
glibc-2.38/
nss/
getent.c
       1  /* Copyright (c) 1998-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  /* getent: get entries from administrative database.  */
      19  
      20  #include <aliases.h>
      21  #include <argp.h>
      22  #include <ctype.h>
      23  #include <error.h>
      24  #include <grp.h>
      25  #include <gshadow.h>
      26  #include <libintl.h>
      27  #include <locale.h>
      28  #include <mcheck.h>
      29  #include <netdb.h>
      30  #include <pwd.h>
      31  #include <shadow.h>
      32  #include <stdbool.h>
      33  #include <stdio.h>
      34  #include <stdlib.h>
      35  #include <string.h>
      36  #include <arpa/inet.h>
      37  #include <arpa/nameser.h>
      38  #include <netinet/ether.h>
      39  #include <netinet/in.h>
      40  #include <sys/socket.h>
      41  #include <scratch_buffer.h>
      42  #include <inttypes.h>
      43  
      44  /* Get libc version number.  */
      45  #include <version.h>
      46  
      47  #define PACKAGE _libc_intl_domainname
      48  
      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;
      52  
      53  /* Short description of parameters.  */
      54  static const char args_doc[] = N_("database [key ...]");
      55  
      56  /* Supported options. */
      57  static const struct argp_option args_options[] =
      58    {
      59      { "service", 's', N_("CONFIG"), 0, N_("Service configuration to be used") },
      60      { "no-idn", 'i', NULL, 0, N_("disable IDN encoding") },
      61      { "no-addrconfig", 'A', NULL, 0,
      62        N_("do not filter out unsupported IPv4/IPv6 addresses (with ahosts*)") },
      63      { NULL, 0, NULL, 0, NULL },
      64    };
      65  
      66  /* Short description of program.  */
      67  static const char doc[] = N_("Get entries from administrative database.");
      68  
      69  /* Prototype for option handler.  */
      70  static error_t parse_option (int key, char *arg, struct argp_state *state);
      71  
      72  /* Function to print some extra text in the help message.  */
      73  static char *more_help (int key, const char *text, void *input);
      74  
      75  /* Data structure to communicate with argp functions.  */
      76  static struct argp argp =
      77    {
      78      args_options, parse_option, args_doc, doc, NULL, more_help
      79    };
      80  
      81  /* Additional getaddrinfo flags for IDN encoding.  */
      82  static int idn_flags = AI_IDN | AI_CANONIDN;
      83  
      84  /* Set to 0 by --no-addrconfig.  */
      85  static int addrconfig_flags = AI_ADDRCONFIG;
      86  
      87  /* Print the version information.  */
      88  static void
      89  print_version (FILE *stream, struct argp_state *state)
      90  {
      91    fprintf (stream, "getent %s%s\n", PKGVERSION, VERSION);
      92    fprintf (stream, gettext ("\
      93  Copyright (C) %s Free Software Foundation, Inc.\n\
      94  This is free software; see the source for copying conditions.  There is NO\n\
      95  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
      96  "), "2023");
      97    fprintf (stream, gettext ("Written by %s.\n"), "Thorsten Kukuk");
      98  }
      99  
     100  /* This is for aliases */
     101  static void
     102  print_aliases (struct aliasent *alias)
     103  {
     104    unsigned int i = 0;
     105  
     106    printf ("%s: ", alias->alias_name);
     107    for  (i = strlen (alias->alias_name); i < 14; ++i)
     108      fputs_unlocked (" ", stdout);
     109  
     110    for (i = 0; i < alias->alias_members_len; ++i)
     111      printf ("%s%s",
     112  	    alias->alias_members [i],
     113  	    i + 1 == alias->alias_members_len ? "\n" : ", ");
     114  }
     115  
     116  static int
     117  aliases_keys (int number, char *key[])
     118  {
     119    int result = 0;
     120    int i;
     121    struct aliasent *alias;
     122  
     123    if (number == 0)
     124      {
     125        setaliasent ();
     126        while ((alias = getaliasent ()) != NULL)
     127  	print_aliases (alias);
     128        endaliasent ();
     129        return result;
     130      }
     131  
     132    for (i = 0; i < number; ++i)
     133      {
     134        alias = getaliasbyname (key[i]);
     135  
     136        if (alias == NULL)
     137  	result = 2;
     138        else
     139  	print_aliases (alias);
     140      }
     141  
     142    return result;
     143  }
     144  
     145  /* This is for ethers */
     146  static int
     147  ethers_keys (int number, char *key[])
     148  {
     149    int result = 0;
     150    int i;
     151  
     152    if (number == 0)
     153      {
     154        fprintf (stderr, _("Enumeration not supported on %s\n"), "ethers");
     155        return 3;
     156      }
     157  
     158    for (i = 0; i < number; ++i)
     159      {
     160        struct ether_addr *ethp, eth;
     161        char buffer [1024], *p;
     162  
     163        ethp = ether_aton (key[i]);
     164        if (ethp != NULL)
     165  	{
     166  	  if (ether_ntohost (buffer, ethp))
     167  	    {
     168  	      result = 2;
     169  	      continue;
     170  	    }
     171  	  p = buffer;
     172  	}
     173        else
     174  	{
     175  	  if (ether_hostton (key[i], &eth))
     176  	    {
     177  	      result = 2;
     178  	      continue;
     179  	    }
     180  	  p = key[i];
     181  	  ethp = &eth;
     182  	}
     183        printf ("%s %s\n", ether_ntoa (ethp), p);
     184      }
     185  
     186    return result;
     187  }
     188  
     189  /* This is for group */
     190  static void
     191  print_group (struct group *grp)
     192  {
     193    if (putgrent (grp, stdout) != 0)
     194      fprintf (stderr, "error writing group entry: %m\n");
     195  }
     196  
     197  static int
     198  group_keys (int number, char *key[])
     199  {
     200    int result = 0;
     201    int i;
     202    struct group *grp;
     203  
     204    if (number == 0)
     205      {
     206        setgrent ();
     207        while ((grp = getgrent ()) != NULL)
     208  	print_group (grp);
     209        endgrent ();
     210        return result;
     211      }
     212  
     213    for (i = 0; i < number; ++i)
     214      {
     215        errno = 0;
     216        char *ep;
     217        gid_t arg_gid = strtoul(key[i], &ep, 10);
     218  
     219        if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
     220  	/* Valid numeric gid.  */
     221  	grp = getgrgid (arg_gid);
     222        else
     223  	grp = getgrnam (key[i]);
     224  
     225        if (grp == NULL)
     226  	result = 2;
     227        else
     228  	print_group (grp);
     229      }
     230  
     231    return result;
     232  }
     233  
     234  /* This is for gshadow */
     235  static void
     236  print_gshadow (struct sgrp *sg)
     237  {
     238    if (putsgent (sg, stdout) != 0)
     239      fprintf (stderr, "error writing gshadow entry: %m\n");
     240  }
     241  
     242  static int
     243  gshadow_keys (int number, char *key[])
     244  {
     245    int result = 0;
     246    int i;
     247  
     248    if (number == 0)
     249      {
     250        struct sgrp *sg;
     251  
     252        setsgent ();
     253        while ((sg = getsgent ()) != NULL)
     254  	print_gshadow (sg);
     255        endsgent ();
     256        return result;
     257      }
     258  
     259    for (i = 0; i < number; ++i)
     260      {
     261        struct sgrp *sg;
     262  
     263        sg = getsgnam (key[i]);
     264  
     265        if (sg == NULL)
     266  	result = 2;
     267        else
     268  	print_gshadow (sg);
     269      }
     270  
     271    return result;
     272  }
     273  
     274  /* This is for hosts */
     275  static void
     276  print_hosts (struct hostent *host)
     277  {
     278    unsigned int cnt;
     279  
     280    for (cnt = 0; host->h_addr_list[cnt] != NULL; ++cnt)
     281      {
     282        char buf[INET6_ADDRSTRLEN];
     283        const char *ip = inet_ntop (host->h_addrtype, host->h_addr_list[cnt],
     284  				  buf, sizeof (buf));
     285  
     286        printf ("%-15s %s", ip, host->h_name);
     287  
     288        unsigned int i;
     289        for (i = 0; host->h_aliases[i] != NULL; ++i)
     290  	{
     291  	  putchar_unlocked (' ');
     292  	  fputs_unlocked (host->h_aliases[i], stdout);
     293  	}
     294        putchar_unlocked ('\n');
     295      }
     296  }
     297  
     298  static int
     299  hosts_keys (int number, char *key[])
     300  {
     301    int result = 0;
     302    int i;
     303    struct hostent *host;
     304  
     305    if (number == 0)
     306      {
     307        sethostent (0);
     308        while ((host = gethostent ()) != NULL)
     309  	print_hosts (host);
     310        endhostent ();
     311        return result;
     312      }
     313  
     314    for (i = 0; i < number; ++i)
     315      {
     316        struct hostent *host = NULL;
     317        char addr[IN6ADDRSZ];
     318  
     319        if (inet_pton (AF_INET6, key[i], &addr) > 0)
     320  	host = gethostbyaddr (addr, IN6ADDRSZ, AF_INET6);
     321        else if (inet_pton (AF_INET, key[i], &addr) > 0)
     322  	host = gethostbyaddr (addr, INADDRSZ, AF_INET);
     323        else if ((host = gethostbyname2 (key[i], AF_INET6)) == NULL)
     324  	host = gethostbyname2 (key[i], AF_INET);
     325  
     326        if (host == NULL)
     327  	result = 2;
     328        else
     329  	print_hosts (host);
     330      }
     331  
     332    return result;
     333  }
     334  
     335  /* This is for hosts, but using getaddrinfo */
     336  static int
     337  ahosts_keys_int (int af, int xflags, int number, char *key[])
     338  {
     339    int result = 0;
     340    int i;
     341    struct hostent *host;
     342  
     343    if (number == 0)
     344      {
     345        sethostent (0);
     346        while ((host = gethostent ()) != NULL)
     347  	print_hosts (host);
     348        endhostent ();
     349        return result;
     350      }
     351  
     352    struct addrinfo hint;
     353    memset (&hint, '\0', sizeof (hint));
     354    hint.ai_flags = (AI_V4MAPPED | addrconfig_flags | AI_CANONNAME
     355  		   | idn_flags | xflags);
     356    hint.ai_family = af;
     357  
     358    for (i = 0; i < number; ++i)
     359      {
     360        struct addrinfo *res;
     361  
     362        if (getaddrinfo (key[i], NULL, &hint, &res) != 0)
     363  	result = 2;
     364        else
     365  	{
     366  	  struct addrinfo *runp = res;
     367  
     368  	  while (runp != NULL)
     369  	    {
     370  	      char sockbuf[20];
     371  	      const char *sockstr;
     372  	      if (runp->ai_socktype == SOCK_STREAM)
     373  		sockstr = "STREAM";
     374  	      else if (runp->ai_socktype == SOCK_DGRAM)
     375  		sockstr = "DGRAM";
     376  	      else if (runp->ai_socktype == SOCK_RAW)
     377  		sockstr = "RAW";
     378  #ifdef SOCK_SEQPACKET
     379  	      else if (runp->ai_socktype == SOCK_SEQPACKET)
     380  		sockstr = "SEQPACKET";
     381  #endif
     382  #ifdef SOCK_RDM
     383  	      else if (runp->ai_socktype == SOCK_RDM)
     384  		sockstr = "RDM";
     385  #endif
     386  #ifdef SOCK_DCCP
     387  	      else if (runp->ai_socktype == SOCK_DCCP)
     388  		sockstr = "DCCP";
     389  #endif
     390  #ifdef SOCK_PACKET
     391  	      else if (runp->ai_socktype == SOCK_PACKET)
     392  		sockstr = "PACKET";
     393  #endif
     394  	      else
     395  		{
     396  		  snprintf (sockbuf, sizeof (sockbuf), "%d",
     397  			    runp->ai_socktype);
     398  		  sockstr = sockbuf;
     399  		}
     400  
     401  	      /* Three digits per byte, plus '%' and null terminator.  */
     402  	      char scope[3 * sizeof (uint32_t) + 2];
     403  	      struct sockaddr_in6 *addr6
     404  		= (struct sockaddr_in6 *) runp->ai_addr;
     405  	      if (runp->ai_family != AF_INET6 || addr6->sin6_scope_id == 0)
     406  		/* No scope ID present.  */
     407  		scope[0] = '\0';
     408  	      else
     409  		snprintf (scope, sizeof (scope), "%%%" PRIu32,
     410  			  addr6->sin6_scope_id);
     411  
     412  	      char buf[INET6_ADDRSTRLEN];
     413  	      if (inet_ntop (runp->ai_family,
     414  			     runp->ai_family == AF_INET
     415  			     ? (void *) &((struct sockaddr_in *) runp->ai_addr)->sin_addr
     416  			     : &addr6->sin6_addr,
     417  			     buf, sizeof (buf)) == NULL)
     418  		{
     419  		  strcpy (buf, "<invalid>");
     420  		  scope[0] = '\0';
     421  		}
     422  
     423  	      int pad = 15 - strlen (buf) - strlen (scope);
     424  	      if (pad < 0)
     425  		pad = 0;
     426  
     427  	      printf ("%s%-*s %-6s %s\n",
     428  		      buf, pad, scope, sockstr, runp->ai_canonname ?: "");
     429  
     430  	      runp = runp->ai_next;
     431  	    }
     432  
     433  	  freeaddrinfo (res);
     434  	}
     435      }
     436  
     437    return result;
     438  }
     439  
     440  static int
     441  ahosts_keys (int number, char *key[])
     442  {
     443    return ahosts_keys_int (AF_UNSPEC, 0, number, key);
     444  }
     445  
     446  static int
     447  ahostsv4_keys (int number, char *key[])
     448  {
     449    return ahosts_keys_int (AF_INET, 0, number, key);
     450  }
     451  
     452  static int
     453  ahostsv6_keys (int number, char *key[])
     454  {
     455    return ahosts_keys_int (AF_INET6, AI_V4MAPPED, number, key);
     456  }
     457  
     458  /* This is for netgroup */
     459  static int
     460  netgroup_keys (int number, char *key[])
     461  {
     462    int result = 0;
     463  
     464    if (number == 0)
     465      {
     466        fprintf (stderr, _("Enumeration not supported on %s\n"), "netgroup");
     467        return 3;
     468      }
     469  
     470    if (number == 4)
     471      {
     472        char *host = strcmp (key[1], "*") == 0 ? NULL : key[1];
     473        char *user = strcmp (key[2], "*") == 0 ? NULL : key[2];
     474        char *domain = strcmp (key[3], "*") == 0 ? NULL : key[3];
     475  
     476        printf ("%-21s (%s,%s,%s) = %d\n",
     477  	      key[0], host ?: "", user ?: "", domain ?: "",
     478  	      innetgr (key[0], host, user, domain));
     479      }
     480    else if (number == 1)
     481      {
     482        if (!setnetgrent (key[0]))
     483  	result = 2;
     484        else
     485  	{
     486  	  char *p[3];
     487  
     488  	  printf ("%-21s", key[0]);
     489  
     490  	  while (getnetgrent (p, p + 1, p + 2))
     491  	    printf (" (%s,%s,%s)", p[0] ?: " ", p[1] ?: "", p[2] ?: "");
     492  	  putchar_unlocked ('\n');
     493  	}
     494      }
     495  
     496    endnetgrent ();
     497  
     498    return result;
     499  }
     500  
     501  #define DYNARRAY_STRUCT gid_list
     502  #define DYNARRAY_ELEMENT gid_t
     503  #define DYNARRAY_PREFIX gid_list_
     504  #define DYNARRAY_INITIAL_SIZE 10
     505  #include <malloc/dynarray-skeleton.c>
     506  
     507  /* This is for initgroups */
     508  static int
     509  initgroups_keys (int number, char *key[])
     510  {
     511    if (number == 0)
     512      {
     513        fprintf (stderr, _("Enumeration not supported on %s\n"), "initgroups");
     514        return 3;
     515      }
     516  
     517    struct gid_list list;
     518    gid_list_init (&list);
     519    if (!gid_list_resize (&list, 10))
     520      {
     521        fprintf (stderr, _("Could not allocate group list: %m\n"));
     522        return 3;
     523      }
     524  
     525    for (int i = 0; i < number; ++i)
     526      {
     527        int no = gid_list_size (&list);
     528        int n;
     529        while ((n = getgrouplist (key[i], -1, gid_list_begin (&list), &no)) == -1
     530  	     && no > gid_list_size (&list))
     531  	{
     532  	  if (!gid_list_resize (&list, no))
     533  	    {
     534  	      fprintf (stderr, _("Could not allocate group list: %m\n"));
     535  	      return 3;
     536  	    }
     537  	}
     538  
     539        if (n == -1)
     540  	{
     541  	  gid_list_free (&list);
     542  	  return 1;
     543  	}
     544  
     545        const gid_t *grps = gid_list_begin (&list);
     546        printf ("%-21s", key[i]);
     547        for (int j = 0; j < n; ++j)
     548  	if (grps[j] != -1)
     549  	  printf (" %ld", (long int) grps[j]);
     550        putchar_unlocked ('\n');
     551      }
     552  
     553    gid_list_free (&list);
     554  
     555    return 0;
     556  }
     557  
     558  /* This is for networks */
     559  static void
     560  print_networks (struct netent *net)
     561  {
     562    unsigned int i;
     563    struct in_addr ip;
     564    ip.s_addr = htonl (net->n_net);
     565  
     566    printf ("%-21s %s", net->n_name, inet_ntoa (ip));
     567  
     568    i = 0;
     569    while (net->n_aliases[i] != NULL)
     570      {
     571        putchar_unlocked (' ');
     572        fputs_unlocked (net->n_aliases[i], stdout);
     573        ++i;
     574      }
     575    putchar_unlocked ('\n');
     576  }
     577  
     578  static int
     579  networks_keys (int number, char *key[])
     580  {
     581    int result = 0;
     582    int i;
     583    struct netent *net;
     584  
     585    if (number == 0)
     586      {
     587        setnetent (0);
     588        while ((net = getnetent ()) != NULL)
     589  	print_networks (net);
     590        endnetent ();
     591        return result;
     592      }
     593  
     594    for (i = 0; i < number; ++i)
     595      {
     596        if (isdigit (key[i][0]))
     597  	net = getnetbyaddr (ntohl (inet_addr (key[i])), AF_UNSPEC);
     598        else
     599  	net = getnetbyname (key[i]);
     600  
     601        if (net == NULL)
     602  	result = 2;
     603        else
     604  	print_networks (net);
     605      }
     606  
     607    return result;
     608  }
     609  
     610  /* Now is all for passwd */
     611  static void
     612  print_passwd (struct passwd *pwd)
     613  {
     614    if (putpwent (pwd, stdout) != 0)
     615      fprintf (stderr, "error writing passwd entry: %m\n");
     616  }
     617  
     618  static int
     619  passwd_keys (int number, char *key[])
     620  {
     621    int result = 0;
     622    int i;
     623    struct passwd *pwd;
     624  
     625    if (number == 0)
     626      {
     627        setpwent ();
     628        while ((pwd = getpwent ()) != NULL)
     629  	print_passwd (pwd);
     630        endpwent ();
     631        return result;
     632      }
     633  
     634    for (i = 0; i < number; ++i)
     635      {
     636        errno = 0;
     637        char *ep;
     638        uid_t arg_uid = strtoul(key[i], &ep, 10);
     639  
     640        if (errno != EINVAL && *key[i] != '\0' && *ep == '\0')
     641  	/* Valid numeric uid.  */
     642  	pwd = getpwuid (arg_uid);
     643        else
     644  	pwd = getpwnam (key[i]);
     645  
     646        if (pwd == NULL)
     647  	result = 2;
     648        else
     649  	print_passwd (pwd);
     650      }
     651  
     652    return result;
     653  }
     654  
     655  /* This is for protocols */
     656  static void
     657  print_protocols (struct protoent *proto)
     658  {
     659    unsigned int i;
     660  
     661    printf ("%-21s %d", proto->p_name, proto->p_proto);
     662  
     663    i = 0;
     664    while (proto->p_aliases[i] != NULL)
     665      {
     666        putchar_unlocked (' ');
     667        fputs_unlocked (proto->p_aliases[i], stdout);
     668        ++i;
     669      }
     670    putchar_unlocked ('\n');
     671  }
     672  
     673  static int
     674  protocols_keys (int number, char *key[])
     675  {
     676    int result = 0;
     677    int i;
     678    struct protoent *proto;
     679  
     680    if (number == 0)
     681      {
     682        setprotoent (0);
     683        while ((proto = getprotoent ()) != NULL)
     684  	print_protocols (proto);
     685        endprotoent ();
     686        return result;
     687      }
     688  
     689    for (i = 0; i < number; ++i)
     690      {
     691        if (isdigit (key[i][0]))
     692  	proto = getprotobynumber (atol (key[i]));
     693        else
     694  	proto = getprotobyname (key[i]);
     695  
     696        if (proto == NULL)
     697  	result = 2;
     698        else
     699  	print_protocols (proto);
     700      }
     701  
     702    return result;
     703  }
     704  
     705  #if HAVE_SUNRPC
     706  /* Now is all for rpc */
     707  static void
     708  print_rpc (struct rpcent *rpc)
     709  {
     710    int i;
     711  
     712    printf ("%-15s %d%s",
     713  	  rpc->r_name, rpc->r_number, rpc->r_aliases[0] ? " " : "");
     714  
     715    for (i = 0; rpc->r_aliases[i]; ++i)
     716      printf (" %s", rpc->r_aliases[i]);
     717    putchar_unlocked ('\n');
     718  }
     719  
     720  static int
     721  rpc_keys (int number, char *key[])
     722  {
     723    int result = 0;
     724    int i;
     725    struct rpcent *rpc;
     726  
     727    if (number == 0)
     728      {
     729        setrpcent (0);
     730        while ((rpc = getrpcent ()) != NULL)
     731  	print_rpc (rpc);
     732        endrpcent ();
     733        return result;
     734      }
     735  
     736    for (i = 0; i < number; ++i)
     737      {
     738        if (isdigit (key[i][0]))
     739  	rpc = getrpcbynumber (atol (key[i]));
     740        else
     741  	rpc = getrpcbyname (key[i]);
     742  
     743        if (rpc == NULL)
     744  	result = 2;
     745        else
     746  	print_rpc (rpc);
     747      }
     748  
     749    return result;
     750  }
     751  #endif
     752  
     753  /* for services */
     754  static void
     755  print_services (struct servent *serv)
     756  {
     757    unsigned int i;
     758  
     759    printf ("%-21s %d/%s", serv->s_name, ntohs (serv->s_port), serv->s_proto);
     760  
     761    i = 0;
     762    while (serv->s_aliases[i] != NULL)
     763      {
     764        putchar_unlocked (' ');
     765        fputs_unlocked (serv->s_aliases[i], stdout);
     766        ++i;
     767      }
     768    putchar_unlocked ('\n');
     769  }
     770  
     771  static int
     772  services_keys (int number, char *key[])
     773  {
     774    int result = 0;
     775    int i;
     776    struct servent *serv;
     777  
     778    if (!number)
     779      {
     780        setservent (0);
     781        while ((serv = getservent ()) != NULL)
     782  	print_services (serv);
     783        endservent ();
     784        return result;
     785      }
     786  
     787    for (i = 0; i < number; ++i)
     788      {
     789        struct servent *serv;
     790        char *proto = strchr (key[i], '/');
     791  
     792        if (proto != NULL)
     793  	*proto++ = '\0';
     794  
     795        char *endptr;
     796        long port = strtol (key[i], &endptr, 10);
     797  
     798        if (isdigit (key[i][0]) && *endptr == '\0'
     799  	  && 0 <= port && port <= 65535)
     800  	serv = getservbyport (htons (port), proto);
     801        else
     802  	serv = getservbyname (key[i], proto);
     803  
     804        if (serv == NULL)
     805  	result = 2;
     806        else
     807  	print_services (serv);
     808      }
     809  
     810    return result;
     811  }
     812  
     813  /* This is for shadow */
     814  static void
     815  print_shadow (struct spwd *sp)
     816  {
     817    if (putspent (sp, stdout) != 0)
     818      fprintf (stderr, "error writing shadow entry: %m\n");
     819  }
     820  
     821  static int
     822  shadow_keys (int number, char *key[])
     823  {
     824    int result = 0;
     825    int i;
     826  
     827    if (number == 0)
     828      {
     829        struct spwd *sp;
     830  
     831        setspent ();
     832        while ((sp = getspent ()) != NULL)
     833  	print_shadow (sp);
     834        endspent ();
     835        return result;
     836      }
     837  
     838    for (i = 0; i < number; ++i)
     839      {
     840        struct spwd *sp;
     841  
     842        sp = getspnam (key[i]);
     843  
     844        if (sp == NULL)
     845  	result = 2;
     846        else
     847  	print_shadow (sp);
     848      }
     849  
     850    return result;
     851  }
     852  
     853  struct
     854    {
     855      const char *name;
     856      int (*func) (int number, char *key[]);
     857    } databases[] =
     858    {
     859  #define D(name) { #name, name ## _keys },
     860  D(ahosts)
     861  D(ahostsv4)
     862  D(ahostsv6)
     863  D(aliases)
     864  D(ethers)
     865  D(group)
     866  D(gshadow)
     867  D(hosts)
     868  D(initgroups)
     869  D(netgroup)
     870  D(networks)
     871  D(passwd)
     872  D(protocols)
     873  #if HAVE_SUNRPC
     874  D(rpc)
     875  #endif
     876  D(services)
     877  D(shadow)
     878  #undef D
     879      { NULL, NULL }
     880    };
     881  
     882  /* Handle arguments found by argp. */
     883  static error_t
     884  parse_option (int key, char *arg, struct argp_state *state)
     885  {
     886    char *endp;
     887    switch (key)
     888      {
     889      case 's':
     890        endp = strchr (arg, ':');
     891        if (endp == NULL)
     892  	/* No specific database, change them all.  */
     893  	for (int i = 0; databases[i].name != NULL; ++i)
     894  	  __nss_configure_lookup (databases[i].name, arg);
     895        else
     896  	{
     897  	  int i;
     898  	  for (i = 0; databases[i].name != NULL; ++i)
     899  	    if (strncmp (databases[i].name, arg, endp - arg) == 0)
     900  	      {
     901  		__nss_configure_lookup (databases[i].name, endp + 1);
     902  		break;
     903  	      }
     904  	  if (databases[i].name == NULL)
     905  	    error (EXIT_FAILURE, 0, gettext ("Unknown database name"));
     906  	}
     907        break;
     908  
     909      case 'i':
     910        idn_flags = 0;
     911        break;
     912  
     913      case 'A':
     914        addrconfig_flags = 0;
     915        break;
     916  
     917      default:
     918        return ARGP_ERR_UNKNOWN;
     919      }
     920  
     921    return 0;
     922  }
     923  
     924  
     925  static char *
     926  more_help (int key, const char *text, void *input)
     927  {
     928    switch (key)
     929      {
     930        size_t len;
     931        char *doc;
     932        FILE *fp;
     933  
     934      case ARGP_KEY_HELP_EXTRA:
     935        /* We print some extra information.  */
     936        fp = open_memstream (&doc, &len);
     937        if (fp != NULL)
     938  	{
     939  	  fputs_unlocked (_("Supported databases:\n"), fp);
     940  
     941  	  for (int i = 0, col = 0; databases[i].name != NULL; ++i)
     942  	    {
     943  	      len = strlen (databases[i].name);
     944  	      if (i != 0)
     945  		{
     946  		  if (col + len > 72)
     947  		    {
     948  		      col = 0;
     949  		      fputc_unlocked ('\n', fp);
     950  		    }
     951  		  else
     952  		    fputc_unlocked (' ', fp);
     953  		}
     954  
     955  	      fputs_unlocked (databases[i].name, fp);
     956  	      col += len + 1;
     957  	    }
     958  
     959  	  fputs ("\n\n", fp);
     960  
     961  	  fprintf (fp, gettext ("\
     962  For bug reporting instructions, please see:\n\
     963  %s.\n"), REPORT_BUGS_TO);
     964  
     965  	  if (fclose (fp) == 0)
     966  	    return doc;
     967  	}
     968        break;
     969  
     970      default:
     971        break;
     972      }
     973    return (char *) text;
     974  }
     975  
     976  
     977  /* the main function */
     978  int
     979  main (int argc, char *argv[])
     980  {
     981    /* Debugging support.  */
     982    mtrace ();
     983  
     984    /* Set locale via LC_ALL.  */
     985    setlocale (LC_ALL, "");
     986    /* Set the text message domain.  */
     987    textdomain (PACKAGE);
     988  
     989    /* Parse and process arguments.  */
     990    int remaining;
     991    argp_parse (&argp, argc, argv, 0, &remaining, NULL);
     992  
     993    if ((argc - remaining) < 1)
     994      {
     995        error (0, 0, gettext ("wrong number of arguments"));
     996        argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
     997        return 1;
     998      }
     999  
    1000    for (int i = 0; databases[i].name; ++i)
    1001      if (argv[remaining][0] == databases[i].name[0]
    1002  	&& !strcmp (argv[remaining], databases[i].name))
    1003        return databases[i].func (argc - remaining - 1, &argv[remaining + 1]);
    1004  
    1005    fprintf (stderr, _("Unknown database: %s\n"), argv[remaining]);
    1006    argp_help (&argp, stdout, ARGP_HELP_SEE, program_invocation_short_name);
    1007    return 1;
    1008  }