Blame nss/nss_files/files-hosts.c

Packit 6c4009
/* Hosts file parser in nss_files module.
Packit 6c4009
   Copyright (C) 1996-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
#include <assert.h>
Packit 6c4009
#include <netinet/in.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
#include <arpa/nameser.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <resolv/resolv-internal.h>
Packit 6c4009
#include <scratch_buffer.h>
Packit 6c4009
#include <alloc_buffer.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Get implementation for some internal functions.  */
Packit 6c4009
#include "../resolv/mapv4v6addr.h"
Packit 6c4009
#include "../resolv/res_hconf.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define ENTNAME		hostent
Packit 6c4009
#define DATABASE	"hosts"
Packit 6c4009
#define NEED_H_ERRNO
Packit 6c4009
Packit 6c4009
#define EXTRA_ARGS	 , af, flags
Packit 6c4009
#define EXTRA_ARGS_DECL	 , int af, int flags
Packit 6c4009
Packit 6c4009
#define ENTDATA hostent_data
Packit 6c4009
struct hostent_data
Packit 6c4009
  {
Packit 6c4009
    unsigned char host_addr[16]; /* IPv4 or IPv6 address.  */
Packit 6c4009
    char *h_addr_ptrs[2];	/* Points to that and null terminator.  */
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
#define TRAILING_LIST_MEMBER		h_aliases
Packit 6c4009
#define TRAILING_LIST_SEPARATOR_P	isspace
Packit 6c4009
#include "files-parse.c"
Packit 6c4009
LINE_PARSER
Packit 6c4009
("#",
Packit 6c4009
 {
Packit 6c4009
   char *addr;
Packit 6c4009
Packit 6c4009
   STRING_FIELD (addr, isspace, 1);
Packit 6c4009
Packit 6c4009
   /* Parse address.  */
Packit 6c4009
   if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
Packit 6c4009
       > 0)
Packit 6c4009
     af = af == AF_UNSPEC ? AF_INET : af;
Packit 6c4009
   else
Packit 6c4009
     {
Packit 6c4009
       if (af == AF_INET6 && (flags & AI_V4MAPPED) != 0
Packit 6c4009
	   && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
Packit 6c4009
	 map_v4v6_address ((char *) entdata->host_addr,
Packit 6c4009
			   (char *) entdata->host_addr);
Packit 6c4009
       else if (af == AF_INET
Packit 6c4009
		&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
Packit 6c4009
	 {
Packit 6c4009
	   if (IN6_IS_ADDR_V4MAPPED (entdata->host_addr))
Packit 6c4009
	     memcpy (entdata->host_addr, entdata->host_addr + 12, INADDRSZ);
Packit 6c4009
	   else if (IN6_IS_ADDR_LOOPBACK (entdata->host_addr))
Packit 6c4009
	     {
Packit 6c4009
	       in_addr_t localhost = htonl (INADDR_LOOPBACK);
Packit 6c4009
	       memcpy (entdata->host_addr, &localhost, sizeof (localhost));
Packit 6c4009
	     }
Packit 6c4009
	   else
Packit 6c4009
	     /* Illegal address: ignore line.  */
Packit 6c4009
	     return 0;
Packit 6c4009
	 }
Packit 6c4009
       else if (af == AF_UNSPEC
Packit 6c4009
		&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
Packit 6c4009
	 af = AF_INET6;
Packit 6c4009
       else
Packit 6c4009
	 /* Illegal address: ignore line.  */
Packit 6c4009
	 return 0;
Packit 6c4009
     }
Packit 6c4009
Packit 6c4009
   /* We always return entries of the requested form.  */
Packit 6c4009
   result->h_addrtype = af;
Packit 6c4009
   result->h_length = af == AF_INET ? INADDRSZ : IN6ADDRSZ;
Packit 6c4009
Packit 6c4009
   /* Store a pointer to the address in the expected form.  */
Packit 6c4009
   entdata->h_addr_ptrs[0] = (char *) entdata->host_addr;
Packit 6c4009
   entdata->h_addr_ptrs[1] = NULL;
Packit 6c4009
   result->h_addr_list = entdata->h_addr_ptrs;
Packit 6c4009
Packit 6c4009
   STRING_FIELD (result->h_name, isspace, 1);
Packit 6c4009
 })
Packit 6c4009
Packit 6c4009
#define EXTRA_ARGS_VALUE \
Packit 6c4009
  , (res_use_inet6 () ? AF_INET6 : AF_INET),		      \
Packit 6c4009
  (res_use_inet6 () ? AI_V4MAPPED : 0)
Packit 6c4009
#include "files-XXX.c"
Packit 6c4009
#undef EXTRA_ARGS_VALUE
Packit 6c4009
Packit 6c4009
/* We only need to consider IPv4 mapped addresses if the input to the
Packit 6c4009
   gethostbyaddr() function is an IPv6 address.  */
Packit 6c4009
#define EXTRA_ARGS_VALUE \
Packit 6c4009
  , af, (len == IN6ADDRSZ ? AI_V4MAPPED : 0)
Packit 6c4009
DB_LOOKUP (hostbyaddr, ,,,
Packit 6c4009
	   {
Packit 6c4009
	     if (result->h_length == (int) len
Packit 6c4009
		 && ! memcmp (addr, result->h_addr_list[0], len))
Packit 6c4009
	       break;
Packit 6c4009
	   }, const void *addr, socklen_t len, int af)
Packit 6c4009
#undef EXTRA_ARGS_VALUE
Packit 6c4009
Packit 6c4009
/* Type of the address and alias arrays.  */
Packit 6c4009
#define DYNARRAY_STRUCT array
Packit 6c4009
#define DYNARRAY_ELEMENT char *
Packit 6c4009
#define DYNARRAY_PREFIX array_
Packit 6c4009
#include <malloc/dynarray-skeleton.c>
Packit 6c4009
Packit 6c4009
static enum nss_status
Packit 6c4009
gethostbyname3_multi (FILE * stream, const char *name, int af,
Packit 6c4009
		      struct hostent *result, char *buffer, size_t buflen,
Packit 6c4009
		      int *errnop, int *herrnop, int flags)
Packit 6c4009
{
Packit 6c4009
  assert (af == AF_INET || af == AF_INET6);
Packit 6c4009
Packit 6c4009
  /* We have to get all host entries from the file.  */
Packit 6c4009
  struct scratch_buffer tmp_buffer;
Packit 6c4009
  scratch_buffer_init (&tmp_buffer);
Packit 6c4009
  struct hostent tmp_result_buf;
Packit 6c4009
  struct array addresses;
Packit 6c4009
  array_init (&addresses);
Packit 6c4009
  struct array aliases;
Packit 6c4009
  array_init (&aliases);
Packit 6c4009
  enum nss_status status;
Packit 6c4009
Packit 6c4009
  /* Preserve the addresses and aliases encountered so far.  */
Packit 6c4009
  for (size_t i = 0; result->h_addr_list[i] != NULL; ++i)
Packit 6c4009
    array_add (&addresses, result->h_addr_list[i]);
Packit 6c4009
  for (size_t i = 0; result->h_aliases[i] != NULL; ++i)
Packit 6c4009
    array_add (&aliases, result->h_aliases[i]);
Packit 6c4009
Packit 6c4009
  /* The output buffer re-uses now-unused space at the end of the
Packit 6c4009
     buffer, starting with the aliases array.  It comes last in the
Packit 6c4009
     data produced by internal_getent.  (The alias names themselves
Packit 6c4009
     are still located in the line read in internal_getent, which is
Packit 6c4009
     stored at the beginning of the buffer.)  */
Packit 6c4009
  struct alloc_buffer outbuf;
Packit 6c4009
  {
Packit 6c4009
    char *bufferend = (char *) result->h_aliases;
Packit 6c4009
    outbuf = alloc_buffer_create (bufferend, buffer + buflen - bufferend);
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  while (true)
Packit 6c4009
    {
Packit 6c4009
      status = internal_getent (stream, &tmp_result_buf, tmp_buffer.data,
Packit 6c4009
				tmp_buffer.length, errnop, herrnop, af,
Packit 6c4009
				flags);
Packit 6c4009
      /* Enlarge the buffer if necessary.  */
Packit 6c4009
      if (status == NSS_STATUS_TRYAGAIN && *herrnop == NETDB_INTERNAL
Packit 6c4009
	  && *errnop == ERANGE)
Packit 6c4009
	{
Packit 6c4009
	  if (!scratch_buffer_grow (&tmp_buffer))
Packit 6c4009
	    {
Packit 6c4009
	      *errnop = ENOMEM;
Packit 6c4009
	      /* *herrnop and status already have the right value.  */
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  /* Loop around and retry with a larger buffer.  */
Packit 6c4009
	}
Packit 6c4009
      else if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
	{
Packit 6c4009
	  /* A line was read.  Check that it matches the search
Packit 6c4009
	     criteria.  */
Packit 6c4009
Packit 6c4009
	  int matches = 1;
Packit 6c4009
	  struct hostent *old_result = result;
Packit 6c4009
	  result = &tmp_result_buf;
Packit 6c4009
	  /* The following piece is a bit clumsy but we want to use
Packit 6c4009
	     the `LOOKUP_NAME_CASE' value.  The optimizer should do
Packit 6c4009
	     its job.  */
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      LOOKUP_NAME_CASE (h_name, h_aliases)
Packit 6c4009
		result = old_result;
Packit 6c4009
	    }
Packit 6c4009
	  while ((matches = 0));
Packit 6c4009
Packit 6c4009
	  /* If the line matches, we need to copy the addresses and
Packit 6c4009
	     aliases, so that we can reuse tmp_buffer for the next
Packit 6c4009
	     line.  */
Packit 6c4009
	  if (matches)
Packit 6c4009
	    {
Packit 6c4009
	      /* Record the addresses.  */
Packit 6c4009
	      for (size_t i = 0; tmp_result_buf.h_addr_list[i] != NULL; ++i)
Packit 6c4009
		{
Packit 6c4009
		  /* Allocate the target space in the output buffer,
Packit 6c4009
		     depending on the address family.  */
Packit 6c4009
		  void *target;
Packit 6c4009
		  if (af == AF_INET)
Packit 6c4009
		    {
Packit 6c4009
		      assert (tmp_result_buf.h_length == 4);
Packit 6c4009
		      target = alloc_buffer_alloc (&outbuf, struct in_addr);
Packit 6c4009
		    }
Packit 6c4009
		  else if (af == AF_INET6)
Packit 6c4009
		    {
Packit 6c4009
		      assert (tmp_result_buf.h_length == 16);
Packit 6c4009
		      target = alloc_buffer_alloc (&outbuf, struct in6_addr);
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    __builtin_unreachable ();
Packit 6c4009
Packit 6c4009
		  if (target == NULL)
Packit 6c4009
		    {
Packit 6c4009
		      /* Request a larger output buffer.  */
Packit 6c4009
		      *errnop = ERANGE;
Packit 6c4009
		      *herrnop = NETDB_INTERNAL;
Packit 6c4009
		      status = NSS_STATUS_TRYAGAIN;
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
		  memcpy (target, tmp_result_buf.h_addr_list[i],
Packit 6c4009
			  tmp_result_buf.h_length);
Packit 6c4009
		  array_add (&addresses, target);
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Record the aliases.  */
Packit 6c4009
	      for (size_t i = 0; tmp_result_buf.h_aliases[i] != NULL; ++i)
Packit 6c4009
		{
Packit 6c4009
		  char *alias = tmp_result_buf.h_aliases[i];
Packit 6c4009
		  array_add (&aliases,
Packit 6c4009
			     alloc_buffer_copy_string (&outbuf, alias));
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* If the real name is different add, it also to the
Packit 6c4009
		 aliases.  This means that there is a duplication in
Packit 6c4009
		 the alias list but this is really the user's
Packit 6c4009
		 problem.  */
Packit 6c4009
	      {
Packit 6c4009
		char *new_name = tmp_result_buf.h_name;
Packit 6c4009
		if (strcmp (old_result->h_name, new_name) != 0)
Packit 6c4009
		  array_add (&aliases,
Packit 6c4009
			     alloc_buffer_copy_string (&outbuf, new_name));
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	      /* Report memory allocation failures during the
Packit 6c4009
		 expansion of the temporary arrays.  */
Packit 6c4009
	      if (array_has_failed (&addresses) || array_has_failed (&aliases))
Packit 6c4009
		{
Packit 6c4009
		  *errnop = ENOMEM;
Packit 6c4009
		  *herrnop = NETDB_INTERNAL;
Packit 6c4009
		  status = NSS_STATUS_UNAVAIL;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      /* Request a larger output buffer if we ran out of room.  */
Packit 6c4009
	      if (alloc_buffer_has_failed (&outbuf))
Packit 6c4009
		{
Packit 6c4009
		  *errnop = ERANGE;
Packit 6c4009
		  *herrnop = NETDB_INTERNAL;
Packit 6c4009
		  status = NSS_STATUS_TRYAGAIN;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      result = old_result;
Packit 6c4009
	    } /* If match was found.  */
Packit 6c4009
Packit 6c4009
	  /* If no match is found, loop around and fetch another
Packit 6c4009
	     line.  */
Packit 6c4009
Packit 6c4009
	} /* status == NSS_STATUS_SUCCESS.  */
Packit 6c4009
      else
Packit 6c4009
	/* internal_getent returned an error.  */
Packit 6c4009
	break;
Packit 6c4009
    } /* while (true) */
Packit 6c4009
Packit 6c4009
  /* Propagate the NSS_STATUS_TRYAGAIN error to the caller.  It means
Packit 6c4009
     that we may not have loaded the complete result.
Packit 6c4009
     NSS_STATUS_NOTFOUND, however, means that we reached the end of
Packit 6c4009
     the file successfully.  */
Packit 6c4009
  if (status != NSS_STATUS_TRYAGAIN)
Packit 6c4009
    status = NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      /* Copy the address and alias arrays into the output buffer and
Packit 6c4009
	 add NULL terminators.  The pointed-to elements were directly
Packit 6c4009
	 written into the output buffer above and do not need to be
Packit 6c4009
	 copied again.  */
Packit 6c4009
      size_t addresses_count = array_size (&addresses);
Packit 6c4009
      size_t aliases_count = array_size (&aliases);
Packit 6c4009
      char **out_addresses = alloc_buffer_alloc_array
Packit 6c4009
	(&outbuf, char *, addresses_count + 1);
Packit 6c4009
      char **out_aliases = alloc_buffer_alloc_array
Packit 6c4009
	(&outbuf, char *, aliases_count + 1);
Packit 6c4009
      if (out_addresses == NULL || out_aliases == NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* The output buffer is not large enough.  */
Packit 6c4009
	  *errnop = ERANGE;
Packit 6c4009
	  *herrnop = NETDB_INTERNAL;
Packit 6c4009
	  status = NSS_STATUS_TRYAGAIN;
Packit 6c4009
	  /* Fall through to function exit.  */
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Everything is allocated in place.  Make the copies and
Packit 6c4009
	     adjust the array pointers.  */
Packit 6c4009
	  memcpy (out_addresses, array_begin (&addresses),
Packit 6c4009
		  addresses_count * sizeof (char *));
Packit 6c4009
	  out_addresses[addresses_count] = NULL;
Packit 6c4009
	  memcpy (out_aliases, array_begin (&aliases),
Packit 6c4009
		  aliases_count * sizeof (char *));
Packit 6c4009
	  out_aliases[aliases_count] = NULL;
Packit 6c4009
Packit 6c4009
	  result->h_addr_list = out_addresses;
Packit 6c4009
	  result->h_aliases = out_aliases;
Packit 6c4009
Packit 6c4009
	  status = NSS_STATUS_SUCCESS;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  scratch_buffer_free (&tmp_buffer);
Packit 6c4009
  array_free (&addresses);
Packit 6c4009
  array_free (&aliases);
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
Packit 6c4009
			     char *buffer, size_t buflen, int *errnop,
Packit 6c4009
			     int *herrnop, int32_t *ttlp, char **canonp)
Packit 6c4009
{
Packit 6c4009
  FILE *stream = NULL;
Packit 6c4009
  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);
Packit 6c4009
  buffer += pad;
Packit 6c4009
  buflen = buflen > pad ? buflen - pad : 0;
Packit 6c4009
Packit 6c4009
  /* Open file.  */
Packit 6c4009
  enum nss_status status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      /* XXX Is using _res to determine whether we want to convert IPv4
Packit 6c4009
         addresses to IPv6 addresses really the right thing to do?  */
Packit 6c4009
      int flags = (res_use_inet6 () ? AI_V4MAPPED : 0);
Packit 6c4009
Packit 6c4009
      while ((status = internal_getent (stream, result, buffer, buflen, errnop,
Packit 6c4009
					herrnop, af, flags))
Packit 6c4009
	     == NSS_STATUS_SUCCESS)
Packit 6c4009
	{
Packit 6c4009
	  LOOKUP_NAME_CASE (h_name, h_aliases)
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (status == NSS_STATUS_SUCCESS
Packit 6c4009
	  && _res_hconf.flags & HCONF_FLAG_MULTI)
Packit 6c4009
	status = gethostbyname3_multi
Packit 6c4009
	  (stream, name, af, result, buffer, buflen, errnop, herrnop, flags);
Packit 6c4009
Packit 6c4009
      internal_endent (&stream);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (canonp && status == NSS_STATUS_SUCCESS)
Packit 6c4009
    *canonp = result->h_name;
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_gethostbyname_r (const char *name, struct hostent *result,
Packit 6c4009
			    char *buffer, size_t buflen, int *errnop,
Packit 6c4009
			    int *herrnop)
Packit 6c4009
{
Packit 6c4009
  int af = (res_use_inet6 () ? AF_INET6 : AF_INET);
Packit 6c4009
Packit 6c4009
  return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
Packit 6c4009
				      errnop, herrnop, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
Packit 6c4009
			     char *buffer, size_t buflen, int *errnop,
Packit 6c4009
			     int *herrnop)
Packit 6c4009
{
Packit 6c4009
  return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
Packit 6c4009
				      errnop, herrnop, NULL, NULL);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
Packit 6c4009
			     char *buffer, size_t buflen, int *errnop,
Packit 6c4009
			     int *herrnop, int32_t *ttlp)
Packit 6c4009
{
Packit 6c4009
  FILE *stream = NULL;
Packit 6c4009
Packit 6c4009
  /* Open file.  */
Packit 6c4009
  enum nss_status status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      bool any = false;
Packit 6c4009
      bool got_canon = false;
Packit 6c4009
      while (1)
Packit 6c4009
	{
Packit 6c4009
	  /* Align the buffer for the next record.  */
Packit 6c4009
	  uintptr_t pad = (-(uintptr_t) buffer
Packit 6c4009
			   % __alignof__ (struct hostent_data));
Packit 6c4009
	  buffer += pad;
Packit 6c4009
	  buflen = buflen > pad ? buflen - pad : 0;
Packit 6c4009
Packit 6c4009
	  struct hostent result;
Packit 6c4009
	  status = internal_getent (stream, &result, buffer, buflen, errnop,
Packit 6c4009
				    herrnop, AF_UNSPEC, 0);
Packit 6c4009
	  if (status != NSS_STATUS_SUCCESS)
Packit 6c4009
	    break;
Packit 6c4009
Packit 6c4009
	  int naliases = 0;
Packit 6c4009
	  if (__strcasecmp (name, result.h_name) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      for (; result.h_aliases[naliases] != NULL; ++naliases)
Packit 6c4009
		if (! __strcasecmp (name, result.h_aliases[naliases]))
Packit 6c4009
		  break;
Packit 6c4009
	      if (result.h_aliases[naliases] == NULL)
Packit 6c4009
		continue;
Packit 6c4009
Packit 6c4009
	      /* We know this alias exist.  Count it.  */
Packit 6c4009
	      ++naliases;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Determine how much memory has been used so far.  */
Packit 6c4009
	  // XXX It is not necessary to preserve the aliases array
Packit 6c4009
	  while (result.h_aliases[naliases] != NULL)
Packit 6c4009
	    ++naliases;
Packit 6c4009
	  char *bufferend = (char *) &result.h_aliases[naliases + 1];
Packit 6c4009
	  assert (buflen >= bufferend - buffer);
Packit 6c4009
	  buflen -= bufferend - buffer;
Packit 6c4009
	  buffer = bufferend;
Packit 6c4009
Packit 6c4009
	  /* We found something.  */
Packit 6c4009
	  any = true;
Packit 6c4009
Packit 6c4009
	  /* Create the record the caller expects.  There is only one
Packit 6c4009
	     address.  */
Packit 6c4009
	  assert (result.h_addr_list[1] == NULL);
Packit 6c4009
	  if (*pat == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      uintptr_t pad = (-(uintptr_t) buffer
Packit 6c4009
			       % __alignof__ (struct gaih_addrtuple));
Packit 6c4009
	      buffer += pad;
Packit 6c4009
	      buflen = buflen > pad ? buflen - pad : 0;
Packit 6c4009
Packit 6c4009
	      if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
Packit 6c4009
				    0))
Packit 6c4009
		{
Packit 6c4009
		  *errnop = ERANGE;
Packit 6c4009
		  *herrnop = NETDB_INTERNAL;
Packit 6c4009
		  status = NSS_STATUS_TRYAGAIN;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      *pat = (struct gaih_addrtuple *) buffer;
Packit 6c4009
	      buffer += sizeof (struct gaih_addrtuple);
Packit 6c4009
	      buflen -= sizeof (struct gaih_addrtuple);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  (*pat)->next = NULL;
Packit 6c4009
	  (*pat)->name = got_canon ? NULL : result.h_name;
Packit 6c4009
	  got_canon = true;
Packit 6c4009
	  (*pat)->family = result.h_addrtype;
Packit 6c4009
	  memcpy ((*pat)->addr, result.h_addr_list[0], result.h_length);
Packit 6c4009
	  (*pat)->scopeid = 0;
Packit 6c4009
Packit 6c4009
	  pat = &((*pat)->next);
Packit 6c4009
Packit 6c4009
	  /* If we only look for the first matching entry we are done.  */
Packit 6c4009
	  if ((_res_hconf.flags & HCONF_FLAG_MULTI) == 0)
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If we have to look for multiple records and found one, this
Packit 6c4009
	 is a success.  */
Packit 6c4009
      if (status == NSS_STATUS_NOTFOUND && any)
Packit 6c4009
	{
Packit 6c4009
	  assert ((_res_hconf.flags & HCONF_FLAG_MULTI) != 0);
Packit 6c4009
	  status = NSS_STATUS_SUCCESS;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      internal_endent (&stream);
Packit 6c4009
    }
Packit 6c4009
  else if (status == NSS_STATUS_TRYAGAIN)
Packit 6c4009
    {
Packit 6c4009
      *errnop = errno;
Packit 6c4009
      *herrnop = TRY_AGAIN;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      *errnop = errno;
Packit 6c4009
      *herrnop = NO_DATA;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}