Blame nss/tst-nss-files-hosts-getent.c

Packit 6c4009
/* Enumerate /etc/hosts with a long line (bug 18991).
Packit 6c4009
   Copyright (C) 2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <gnu/lib-names.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <nss.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <support/check.h>
Packit 6c4009
#include <support/check_nss.h>
Packit 6c4009
#include <support/namespace.h>
Packit 6c4009
#include <support/support.h>
Packit 6c4009
#include <support/test-driver.h>
Packit 6c4009
#include <support/xmemstream.h>
Packit 6c4009
#include <support/xstdio.h>
Packit 6c4009
#include <support/xunistd.h>
Packit 6c4009
Packit 6c4009
struct support_chroot *chroot_env;
Packit 6c4009
Packit 6c4009
/* Number of alias names in the long line.  This is varied to catch
Packit 6c4009
   different cases where the ERANGE handling can go wrong (line buffer
Packit 6c4009
   length, alias buffer).  */
Packit 6c4009
static int name_count;
Packit 6c4009
Packit 6c4009
/* Write /etc/hosts, from outside of the chroot.  */
Packit 6c4009
static void
Packit 6c4009
write_hosts (void)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = xfopen (chroot_env->path_hosts, "w");
Packit 6c4009
  fputs ("127.0.0.1   localhost localhost.localdomain\n", fp);
Packit 6c4009
  fputs ("192.0.2.2 host2.example.com\n", fp);
Packit 6c4009
  fputs ("192.0.2.1", fp);
Packit 6c4009
  for (int i = 0; i < name_count; ++i)
Packit 6c4009
    fprintf (fp, " host%d.example.com", i);
Packit 6c4009
  fputs ("\n192.0.2.80 www.example.com\n"
Packit 6c4009
         "192.0.2.5 host5.example.com\n"
Packit 6c4009
         "192.0.2.81 www1.example.com\n", fp);
Packit 6c4009
  xfclose (fp);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
const char *host1_expected =
Packit 6c4009
  "name: localhost\n"
Packit 6c4009
  "alias: localhost.localdomain\n"
Packit 6c4009
  "address: 127.0.0.1\n";
Packit 6c4009
const char *host2_expected =
Packit 6c4009
  "name: host2.example.com\n"
Packit 6c4009
  "address: 192.0.2.2\n";
Packit 6c4009
const char *host4_expected =
Packit 6c4009
  "name: www.example.com\n"
Packit 6c4009
  "address: 192.0.2.80\n";
Packit 6c4009
const char *host5_expected =
Packit 6c4009
  "name: host5.example.com\n"
Packit 6c4009
  "address: 192.0.2.5\n";
Packit 6c4009
const char *host6_expected =
Packit 6c4009
  "name: www1.example.com\n"
Packit 6c4009
  "address: 192.0.2.81\n";
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
prepare (int argc, char **argv)
Packit 6c4009
{
Packit 6c4009
  chroot_env = support_chroot_create
Packit 6c4009
    ((struct support_chroot_configuration)
Packit 6c4009
     {
Packit 6c4009
       .resolv_conf = "",
Packit 6c4009
       .hosts = "",             /* Filled in by write_hosts.  */
Packit 6c4009
       .host_conf = "multi on\n",
Packit 6c4009
     });
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* If -1, no sethostent call.  Otherwise, pass do_stayopen as the
Packit 6c4009
   sethostent argument.  */
Packit 6c4009
static int do_stayopen;
Packit 6c4009
Packit 6c4009
/* If non-zero, perform an endostent call.  */
Packit 6c4009
static int do_endent;
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
subprocess_getent (void *closure)
Packit 6c4009
{
Packit 6c4009
  xchroot (chroot_env->path_chroot);
Packit 6c4009
Packit 6c4009
  errno = 0;
Packit 6c4009
  if (do_stayopen >= 0)
Packit 6c4009
    sethostent (do_stayopen);
Packit 6c4009
  TEST_VERIFY (errno == 0);
Packit 6c4009
Packit 6c4009
  int i = 0;
Packit 6c4009
  while (true)
Packit 6c4009
    {
Packit 6c4009
      struct xmemstream expected;
Packit 6c4009
      xopen_memstream (&expected);
Packit 6c4009
      switch (++i)
Packit 6c4009
        {
Packit 6c4009
        case 1:
Packit 6c4009
          fputs (host1_expected, expected.out);
Packit 6c4009
          break;
Packit 6c4009
        case 2:
Packit 6c4009
          fputs (host2_expected, expected.out);
Packit 6c4009
          break;
Packit 6c4009
        case 3:
Packit 6c4009
          fputs ("name: host0.example.com\n", expected.out);
Packit 6c4009
          for (int j = 1; j < name_count; ++j)
Packit 6c4009
            fprintf (expected.out, "alias: host%d.example.com\n", j);
Packit 6c4009
          fputs ("address: 192.0.2.1\n", expected.out);
Packit 6c4009
          break;
Packit 6c4009
        case 4:
Packit 6c4009
          fputs (host4_expected, expected.out);
Packit 6c4009
          break;
Packit 6c4009
        case 5:
Packit 6c4009
          fputs (host5_expected, expected.out);
Packit 6c4009
          break;
Packit 6c4009
        case 6:
Packit 6c4009
          fputs (host6_expected, expected.out);
Packit 6c4009
          break;
Packit 6c4009
        default:
Packit 6c4009
          fprintf (expected.out, "*** unexpected host %d ***\n", i);
Packit 6c4009
          break;
Packit 6c4009
        }
Packit 6c4009
      xfclose_memstream (&expected);
Packit 6c4009
      char *context = xasprintf ("do_stayopen=%d host=%d", do_stayopen, i);
Packit 6c4009
Packit 6c4009
      errno = 0;
Packit 6c4009
      struct hostent *e = gethostent ();
Packit 6c4009
      if (e == NULL)
Packit 6c4009
        {
Packit 6c4009
          TEST_VERIFY (errno == 0);
Packit 6c4009
          break;
Packit 6c4009
        }
Packit 6c4009
      check_hostent (context, e, expected.buffer);
Packit 6c4009
      free (context);
Packit 6c4009
      free (expected.buffer);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  errno = 0;
Packit 6c4009
  if (do_endent)
Packit 6c4009
    endhostent ();
Packit 6c4009
  TEST_VERIFY (errno == 0);
Packit 6c4009
Packit 6c4009
  /* Exercise process termination.   */
Packit 6c4009
  exit (0);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* getaddrinfo test.  To be run from a subprocess.  */
Packit 6c4009
static void
Packit 6c4009
test_gai (int family)
Packit 6c4009
{
Packit 6c4009
  struct addrinfo hints =
Packit 6c4009
    {
Packit 6c4009
      .ai_family = family,
Packit 6c4009
      .ai_protocol = IPPROTO_TCP,
Packit 6c4009
      .ai_socktype = SOCK_STREAM,
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  struct addrinfo *ai;
Packit 6c4009
  int ret = getaddrinfo ("host2.example.com", "80", &hints, &ai;;
Packit 6c4009
  check_addrinfo ("host2.example.com", ai, ret,
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.2 80\n"
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.1 80\n");
Packit 6c4009
Packit 6c4009
  ret = getaddrinfo ("host5.example.com", "80", &hints, &ai;;
Packit 6c4009
  check_addrinfo ("host5.example.com", ai, ret,
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.1 80\n"
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.5 80\n");
Packit 6c4009
Packit 6c4009
  ret = getaddrinfo ("www.example.com", "80", &hints, &ai;;
Packit 6c4009
  check_addrinfo ("www.example.com", ai, ret,
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.80 80\n");
Packit 6c4009
Packit 6c4009
  ret = getaddrinfo ("www1.example.com", "80", &hints, &ai;;
Packit 6c4009
  check_addrinfo ("www1.example.com", ai, ret,
Packit 6c4009
                  "address: STREAM/TCP 192.0.2.81 80\n");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Subprocess routine for gethostbyname/getaddrinfo testing.  */
Packit 6c4009
static void
Packit 6c4009
subprocess_gethost (void *closure)
Packit 6c4009
{
Packit 6c4009
  xchroot (chroot_env->path_chroot);
Packit 6c4009
Packit 6c4009
  /* This tests enlarging the read buffer in the multi case.  */
Packit 6c4009
  struct xmemstream expected;
Packit 6c4009
  xopen_memstream (&expected);
Packit 6c4009
  fputs ("name: host2.example.com\n", expected.out);
Packit 6c4009
  for (int j = 1; j < name_count; ++j)
Packit 6c4009
    /* NB: host2 is duplicated in the alias list.  */
Packit 6c4009
    fprintf (expected.out, "alias: host%d.example.com\n", j);
Packit 6c4009
  fputs ("alias: host0.example.com\n"
Packit 6c4009
         "address: 192.0.2.2\n"
Packit 6c4009
         "address: 192.0.2.1\n",
Packit 6c4009
         expected.out);
Packit 6c4009
  xfclose_memstream (&expected);
Packit 6c4009
  check_hostent ("host2.example.com",
Packit 6c4009
                 gethostbyname ("host2.example.com"),
Packit 6c4009
                 expected.buffer);
Packit 6c4009
  free (expected.buffer);
Packit 6c4009
Packit 6c4009
  /* Similarly, but with a different order in the /etc/hosts file.  */
Packit 6c4009
  xopen_memstream (&expected);
Packit 6c4009
  fputs ("name: host0.example.com\n", expected.out);
Packit 6c4009
  for (int j = 1; j < name_count; ++j)
Packit 6c4009
    fprintf (expected.out, "alias: host%d.example.com\n", j);
Packit 6c4009
  /* NB: host5 is duplicated in the alias list.  */
Packit 6c4009
  fputs ("alias: host5.example.com\n"
Packit 6c4009
         "address: 192.0.2.1\n"
Packit 6c4009
         "address: 192.0.2.5\n",
Packit 6c4009
         expected.out);
Packit 6c4009
  xfclose_memstream (&expected);
Packit 6c4009
  check_hostent ("host5.example.com",
Packit 6c4009
                 gethostbyname ("host5.example.com"),
Packit 6c4009
                 expected.buffer);
Packit 6c4009
  free (expected.buffer);
Packit 6c4009
Packit 6c4009
  check_hostent ("www.example.com",
Packit 6c4009
                 gethostbyname ("www.example.com"),
Packit 6c4009
                 host4_expected);
Packit 6c4009
  check_hostent ("www1.example.com",
Packit 6c4009
                 gethostbyname ("www1.example.com"),
Packit 6c4009
                 host6_expected);
Packit 6c4009
Packit 6c4009
  test_gai (AF_INET);
Packit 6c4009
  test_gai (AF_UNSPEC);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  support_become_root ();
Packit 6c4009
  if (!support_can_chroot ())
Packit 6c4009
    return EXIT_UNSUPPORTED;
Packit 6c4009
Packit 6c4009
  __nss_configure_lookup ("hosts", "files");
Packit 6c4009
  if (dlopen (LIBNSS_FILES_SO, RTLD_LAZY) == NULL)
Packit 6c4009
    FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
Packit 6c4009
Packit 6c4009
  /* Each name takes about 20 bytes, so this covers a wide range of
Packit 6c4009
     buffer sizes, from less than 1000 bytes to about 18000 bytes.  */
Packit 6c4009
  for (name_count = 40; name_count <= 850; ++name_count)
Packit 6c4009
    {
Packit 6c4009
      write_hosts ();
Packit 6c4009
Packit 6c4009
      for (do_stayopen = -1; do_stayopen < 2; ++do_stayopen)
Packit 6c4009
        for (do_endent = 0; do_endent < 2; ++do_endent)
Packit 6c4009
          {
Packit 6c4009
            if (test_verbose > 0)
Packit 6c4009
              printf ("info: name_count=%d do_stayopen=%d do_endent=%d\n",
Packit 6c4009
                      name_count, do_stayopen, do_endent);
Packit 6c4009
            support_isolate_in_subprocess (subprocess_getent, NULL);
Packit 6c4009
          }
Packit 6c4009
Packit 6c4009
      support_isolate_in_subprocess (subprocess_gethost, NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  support_chroot_free (chroot_env);
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define PREPARE prepare
Packit 6c4009
#include <support/test-driver.c>