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