1feee8
commit 32e5db37684ffcbc6ae34fcc6cdcf28670506baa
1feee8
Author: Florian Weimer <fweimer@redhat.com>
1feee8
Date:   Tue Aug 30 10:02:49 2022 +0200
1feee8
1feee8
    nss_dns: Rewrite _nss_dns_gethostbyaddr2_r and getanswer_ptr
1feee8
    
1feee8
    The simplification takes advantage of the split from getanswer_r.
1feee8
    It fixes various aliases issues, and optimizes NSS buffer usage.
1feee8
    The new DNS packet parsing helpers are used, too.
1feee8
    
1feee8
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
1feee8
    (cherry picked from commit e32547d661a43da63368e488b6cfa9c53b4dcf92)
1feee8
1feee8
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
1feee8
index a6bf73a091968358..2cd7170f20b60588 100644
1feee8
--- a/resolv/nss_dns/dns-host.c
1feee8
+++ b/resolv/nss_dns/dns-host.c
1feee8
@@ -70,6 +70,7 @@
1feee8
  * --Copyright--
1feee8
  */
1feee8
 
1feee8
+#include <alloc_buffer.h>
1feee8
 #include <assert.h>
1feee8
 #include <ctype.h>
1feee8
 #include <errno.h>
1feee8
@@ -117,10 +118,9 @@ static enum nss_status getanswer_r (struct resolv_context *ctx,
1feee8
 				    struct hostent *result, char *buffer,
1feee8
 				    size_t buflen, int *errnop, int *h_errnop,
1feee8
 				    int map, int32_t *ttlp, char **canonp);
1feee8
-static enum nss_status getanswer_ptr (const querybuf *answer, int anslen,
1feee8
-				      const char *qname,
1feee8
-				      struct hostent *result, char *buffer,
1feee8
-				      size_t buflen, int *errnop,
1feee8
+static enum nss_status getanswer_ptr (unsigned char *packet, size_t packetlen,
1feee8
+				      struct alloc_buffer *abuf,
1feee8
+				      char **hnamep, int *errnop,
1feee8
 				      int *h_errnop, int32_t *ttlp);
1feee8
 
1feee8
 static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
1feee8
@@ -457,36 +457,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
1feee8
   static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
1feee8
   static const u_char v6local[] = { 0,0, 0,1 };
1feee8
   const u_char *uaddr = (const u_char *)addr;
1feee8
-  struct host_data
1feee8
-  {
1feee8
-    char *aliases[MAX_NR_ALIASES];
1feee8
-    unsigned char host_addr[16];	/* IPv4 or IPv6 */
1feee8
-    char *h_addr_ptrs[MAX_NR_ADDRS + 1];
1feee8
-    char linebuffer[0];
1feee8
-  } *host_data = (struct host_data *) buffer;
1feee8
-  union
1feee8
-  {
1feee8
-    querybuf *buf;
1feee8
-    u_char *ptr;
1feee8
-  } host_buffer;
1feee8
-  querybuf *orig_host_buffer;
1feee8
   char qbuf[MAXDNAME+1], *qp = NULL;
1feee8
   size_t size;
1feee8
   int n, status;
1feee8
   int olderr = errno;
1feee8
 
1feee8
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
1feee8
- buffer += pad;
1feee8
- buflen = buflen > pad ? buflen - pad : 0;
1feee8
-
1feee8
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
1feee8
-   {
1feee8
-     *errnop = ERANGE;
1feee8
-     *h_errnop = NETDB_INTERNAL;
1feee8
-     return NSS_STATUS_TRYAGAIN;
1feee8
-   }
1feee8
-
1feee8
- host_data = (struct host_data *) buffer;
1feee8
+  /* Prepare the allocation buffer.  Store the pointer array first, to
1feee8
+     benefit from buffer alignment.  */
1feee8
+  struct alloc_buffer abuf = alloc_buffer_create (buffer, buflen);
1feee8
+  char **address_array = alloc_buffer_alloc_array (&abuf, char *, 2);
1feee8
+  if (address_array == NULL)
1feee8
+    {
1feee8
+      *errnop = ERANGE;
1feee8
+      *h_errnop = NETDB_INTERNAL;
1feee8
+      return NSS_STATUS_TRYAGAIN;
1feee8
+    }
1feee8
 
1feee8
   struct resolv_context *ctx = __resolv_context_get ();
1feee8
   if (ctx == NULL)
1feee8
@@ -530,8 +515,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
1feee8
       return NSS_STATUS_UNAVAIL;
1feee8
     }
1feee8
 
1feee8
-  host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
1feee8
-
1feee8
   switch (af)
1feee8
     {
1feee8
     case AF_INET:
1feee8
@@ -555,35 +538,52 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
1feee8
       break;
1feee8
     }
1feee8
 
1feee8
-  n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
1feee8
-			   1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
1feee8
+  unsigned char dns_packet_buffer[1024];
1feee8
+  unsigned char *alt_dns_packet_buffer = dns_packet_buffer;
1feee8
+  n = __res_context_query (ctx, qbuf, C_IN, T_PTR,
1feee8
+			   dns_packet_buffer, sizeof (dns_packet_buffer),
1feee8
+			   &alt_dns_packet_buffer,
1feee8
+			   NULL, NULL, NULL, NULL);
1feee8
   if (n < 0)
1feee8
     {
1feee8
       *h_errnop = h_errno;
1feee8
       __set_errno (olderr);
1feee8
-      if (host_buffer.buf != orig_host_buffer)
1feee8
-	free (host_buffer.buf);
1feee8
+      if (alt_dns_packet_buffer != dns_packet_buffer)
1feee8
+	free (alt_dns_packet_buffer);
1feee8
       __resolv_context_put (ctx);
1feee8
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
1feee8
     }
1feee8
 
1feee8
-  status = getanswer_ptr (host_buffer.buf, n, qbuf, result,
1feee8
-			  buffer, buflen, errnop, h_errnop, ttlp);
1feee8
-  if (host_buffer.buf != orig_host_buffer)
1feee8
-    free (host_buffer.buf);
1feee8
+  status = getanswer_ptr (alt_dns_packet_buffer, n,
1feee8
+			  &abuf, &result->h_name, errnop, h_errnop, ttlp);
1feee8
+
1feee8
+  if (alt_dns_packet_buffer != dns_packet_buffer)
1feee8
+    free (alt_dns_packet_buffer);
1feee8
+  __resolv_context_put (ctx);
1feee8
+
1feee8
   if (status != NSS_STATUS_SUCCESS)
1feee8
-    {
1feee8
-      __resolv_context_put (ctx);
1feee8
-      return status;
1feee8
-    }
1feee8
+    return status;
1feee8
 
1feee8
+  /* result->h_name has already been set by getanswer_ptr.  */
1feee8
   result->h_addrtype = af;
1feee8
   result->h_length = len;
1feee8
-  memcpy (host_data->host_addr, addr, len);
1feee8
-  host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
1feee8
-  host_data->h_addr_ptrs[1] = NULL;
1feee8
+  /* Increase the alignment to 4, in case there are applications out
1feee8
+     there that expect at least this level of address alignment.  */
1feee8
+  address_array[0] = (char *) alloc_buffer_next (&abuf, uint32_t);
1feee8
+  alloc_buffer_copy_bytes (&abuf, uaddr, len);
1feee8
+  address_array[1] = NULL;
1feee8
+
1feee8
+  /* This check also covers allocation failure in getanswer_ptr.  */
1feee8
+  if (alloc_buffer_has_failed (&abuf))
1feee8
+    {
1feee8
+      *errnop = ERANGE;
1feee8
+      *h_errnop = NETDB_INTERNAL;
1feee8
+      return NSS_STATUS_TRYAGAIN;
1feee8
+    }
1feee8
+  result->h_addr_list = address_array;
1feee8
+  result->h_aliases = &address_array[1]; /* Points to NULL.  */
1feee8
+
1feee8
   *h_errnop = NETDB_SUCCESS;
1feee8
-  __resolv_context_put (ctx);
1feee8
   return NSS_STATUS_SUCCESS;
1feee8
 }
1feee8
 libc_hidden_def (_nss_dns_gethostbyaddr2_r)
1feee8
@@ -962,287 +962,86 @@ getanswer_r (struct resolv_context *ctx,
1feee8
 }
1feee8
 
1feee8
 static enum nss_status
1feee8
-getanswer_ptr (const querybuf *answer, int anslen, const char *qname,
1feee8
-	       struct hostent *result, char *buffer, size_t buflen,
1feee8
+getanswer_ptr (unsigned char *packet, size_t packetlen,
1feee8
+	       struct alloc_buffer *abuf, char **hnamep,
1feee8
 	       int *errnop, int *h_errnop, int32_t *ttlp)
1feee8
 {
1feee8
-  struct host_data
1feee8
-  {
1feee8
-    char *aliases[MAX_NR_ALIASES];
1feee8
-    unsigned char host_addr[16];	/* IPv4 or IPv6 */
1feee8
-    char *h_addr_ptrs[0];
1feee8
-  } *host_data;
1feee8
-  int linebuflen;
1feee8
-  const HEADER *hp;
1feee8
-  const u_char *end_of_message, *cp;
1feee8
-  int n, ancount, qdcount;
1feee8
-  int haveanswer, had_error;
1feee8
-  char *bp, **ap, **hap;
1feee8
-  char tbuf[MAXDNAME];
1feee8
-  const char *tname;
1feee8
-  u_char packtmp[NS_MAXCDNAME];
1feee8
-  uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
1feee8
-  buffer += pad;
1feee8
-  buflen = buflen > pad ? buflen - pad : 0;
1feee8
-  if (__glibc_unlikely (buflen < sizeof (struct host_data)))
1feee8
-    {
1feee8
-      /* The buffer is too small.  */
1feee8
-    too_small:
1feee8
-      *errnop = ERANGE;
1feee8
-      *h_errnop = NETDB_INTERNAL;
1feee8
-      return NSS_STATUS_TRYAGAIN;
1feee8
-    }
1feee8
-  host_data = (struct host_data *) buffer;
1feee8
-  linebuflen = buflen - sizeof (struct host_data);
1feee8
-  if (buflen - sizeof (struct host_data) != linebuflen)
1feee8
-    linebuflen = INT_MAX;
1feee8
-
1feee8
-  tname = qname;
1feee8
-  result->h_name = NULL;
1feee8
-  end_of_message = answer->buf + anslen;
1feee8
-
1feee8
-  /*
1feee8
-   * find first satisfactory answer
1feee8
-   */
1feee8
-  hp = &answer->hdr;
1feee8
-  ancount = ntohs (hp->ancount);
1feee8
-  qdcount = ntohs (hp->qdcount);
1feee8
-  cp = answer->buf + HFIXEDSZ;
1feee8
-  if (__glibc_unlikely (qdcount != 1))
1feee8
-    {
1feee8
-      *h_errnop = NO_RECOVERY;
1feee8
-      return NSS_STATUS_UNAVAIL;
1feee8
-    }
1feee8
-  if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
1feee8
-    goto too_small;
1feee8
-  bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
1feee8
-  linebuflen -= (ancount + 1) * sizeof (char *);
1feee8
-
1feee8
-  n = __ns_name_unpack (answer->buf, end_of_message, cp,
1feee8
-			packtmp, sizeof packtmp);
1feee8
-  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
1feee8
+  struct ns_rr_cursor c;
1feee8
+  if (!__ns_rr_cursor_init (&c, packet, packetlen))
1feee8
     {
1feee8
-      if (__glibc_unlikely (errno == EMSGSIZE))
1feee8
-	goto too_small;
1feee8
-
1feee8
-      n = -1;
1feee8
-    }
1feee8
-
1feee8
-  if (__glibc_unlikely (n < 0))
1feee8
-    {
1feee8
-      *errnop = errno;
1feee8
-      *h_errnop = NO_RECOVERY;
1feee8
-      return NSS_STATUS_UNAVAIL;
1feee8
-    }
1feee8
-  if (__glibc_unlikely (__libc_res_dnok (bp) == 0))
1feee8
-    {
1feee8
-      errno = EBADMSG;
1feee8
-      *errnop = EBADMSG;
1feee8
+      /* This should not happen because __res_context_query already
1feee8
+	 perfroms response validation.  */
1feee8
       *h_errnop = NO_RECOVERY;
1feee8
       return NSS_STATUS_UNAVAIL;
1feee8
     }
1feee8
-  cp += n + QFIXEDSZ;
1feee8
+  int ancount = ns_rr_cursor_ancount (&c);
1feee8
+  const unsigned char *expected_name = ns_rr_cursor_qname (&c);
1feee8
+  /* expected_name may be updated to point into this buffer.  */
1feee8
+  unsigned char name_buffer[NS_MAXCDNAME];
1feee8
 
1feee8
-  ap = host_data->aliases;
1feee8
-  *ap = NULL;
1feee8
-  result->h_aliases = host_data->aliases;
1feee8
-  hap = host_data->h_addr_ptrs;
1feee8
-  *hap = NULL;
1feee8
-  result->h_addr_list = host_data->h_addr_ptrs;
1feee8
-  haveanswer = 0;
1feee8
-  had_error = 0;
1feee8
-
1feee8
-  while (ancount-- > 0 && cp < end_of_message && had_error == 0)
1feee8
+  while (ancount > 0)
1feee8
     {
1feee8
-      int type, class;
1feee8
-
1feee8
-      n = __ns_name_unpack (answer->buf, end_of_message, cp,
1feee8
-			    packtmp, sizeof packtmp);
1feee8
-      if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
1feee8
+      struct ns_rr_wire rr;
1feee8
+      if (!__ns_rr_cursor_next (&c, &rr))
1feee8
 	{
1feee8
-	  if (__glibc_unlikely (errno == EMSGSIZE))
1feee8
-	    goto too_small;
1feee8
-
1feee8
-	  n = -1;
1feee8
-	}
1feee8
-
1feee8
-      if (__glibc_unlikely (n < 0 || __libc_res_dnok (bp) == 0))
1feee8
-	{
1feee8
-	  ++had_error;
1feee8
-	  continue;
1feee8
-	}
1feee8
-      cp += n;				/* name */
1feee8
-
1feee8
-      if (__glibc_unlikely (cp + 10 > end_of_message))
1feee8
-	{
1feee8
-	  ++had_error;
1feee8
-	  continue;
1feee8
+	  *h_errnop = NO_RECOVERY;
1feee8
+	  return NSS_STATUS_UNAVAIL;
1feee8
 	}
1feee8
 
1feee8
-      NS_GET16 (type, cp);
1feee8
-      NS_GET16 (class, cp);
1feee8
-      int32_t ttl;
1feee8
-      NS_GET32 (ttl, cp);
1feee8
-      NS_GET16 (n, cp);		/* RDATA length.  */
1feee8
+      /* Skip over records with the wrong class.  */
1feee8
+      if (rr.rclass != C_IN)
1feee8
+	continue;
1feee8
 
1feee8
-      if (end_of_message - cp < n)
1feee8
-	{
1feee8
-	  /* RDATA extends beyond the end of the packet.  */
1feee8
-	  ++had_error;
1feee8
-	  continue;
1feee8
-	}
1feee8
-
1feee8
-      if (__glibc_unlikely (class != C_IN))
1feee8
-	{
1feee8
-	  /* XXX - debug? syslog? */
1feee8
-	  cp += n;
1feee8
-	  continue;			/* XXX - had_error++ ? */
1feee8
-	}
1feee8
+      /* Update TTL for known record types.  */
1feee8
+      if ((rr.rtype == T_CNAME || rr.rtype == T_PTR)
1feee8
+	  && ttlp != NULL && *ttlp > rr.ttl)
1feee8
+	*ttlp = rr.ttl;
1feee8
 
1feee8
-      if (type == T_CNAME)
1feee8
+      if (rr.rtype == T_CNAME)
1feee8
 	{
1feee8
-	  /* A CNAME could also have a TTL entry.  */
1feee8
-	  if (ttlp != NULL && ttl < *ttlp)
1feee8
-	      *ttlp = ttl;
1feee8
-
1feee8
-	  n = __libc_dn_expand (answer->buf, end_of_message, cp,
1feee8
-				tbuf, sizeof tbuf);
1feee8
-	  if (__glibc_unlikely (n < 0 || __libc_res_dnok (tbuf) == 0))
1feee8
-	    {
1feee8
-	      ++had_error;
1feee8
-	      continue;
1feee8
-	    }
1feee8
-	  cp += n;
1feee8
-	  /* Get canonical name.  */
1feee8
-	  n = strlen (tbuf) + 1;   /* For the \0.  */
1feee8
-	  if (__glibc_unlikely (n > linebuflen))
1feee8
-	    goto too_small;
1feee8
-	  if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
1feee8
+	  /* NB: No check for owner name match, based on historic
1feee8
+	     precedent.  Record the CNAME target as the new expected
1feee8
+	     name.  */
1feee8
+	  int n = __ns_name_unpack (c.begin, c.end, rr.rdata,
1feee8
+				    name_buffer, sizeof (name_buffer));
1feee8
+	  if (n < 0)
1feee8
 	    {
1feee8
-	      ++had_error;
1feee8
-	      continue;
1feee8
+	      *h_errnop = NO_RECOVERY;
1feee8
+	      return NSS_STATUS_UNAVAIL;
1feee8
 	    }
1feee8
-	  tname = bp;
1feee8
-	  bp = __mempcpy (bp, tbuf, n);	/* Cannot overflow.  */
1feee8
-	  linebuflen -= n;
1feee8
-	  continue;
1feee8
+	  expected_name = name_buffer;
1feee8
 	}
1feee8
-
1feee8
-      switch (type)
1feee8
+      else if (rr.rtype == T_PTR
1feee8
+	       && __ns_samebinaryname (rr.rname, expected_name))
1feee8
 	{
1feee8
-	case T_PTR:
1feee8
-	  if (__glibc_unlikely (__strcasecmp (tname, bp) != 0))
1feee8
-	    {
1feee8
-	      cp += n;
1feee8
-	      continue;			/* XXX - had_error++ ? */
1feee8
-	    }
1feee8
-
1feee8
-	  n = __ns_name_unpack (answer->buf, end_of_message, cp,
1feee8
-				packtmp, sizeof packtmp);
1feee8
-	  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
1feee8
-	    {
1feee8
-	      if (__glibc_unlikely (errno == EMSGSIZE))
1feee8
-		goto too_small;
1feee8
-
1feee8
-	      n = -1;
1feee8
-	    }
1feee8
-
1feee8
-	  if (__glibc_unlikely (n < 0 || __libc_res_hnok (bp) == 0))
1feee8
+	  /* Decompress the target of the PTR record.  This is the
1feee8
+	     host name we are looking for.  We can only use it if it
1feee8
+	     is syntactically valid.  Historically, only one host name
1feee8
+	     is returned here.  If the recursive resolver performs DNS
1feee8
+	     record rotation, the returned host name is essentially
1feee8
+	     random, which is why multiple PTR records are rarely
1feee8
+	     used.  Use MAXHOSTNAMELEN instead of NS_MAXCDNAME for
1feee8
+	     additional length checking.  */
1feee8
+	  char hname[MAXHOSTNAMELEN + 1];
1feee8
+	  if (__ns_name_unpack (c.begin, c.end, rr.rdata,
1feee8
+				name_buffer, sizeof (name_buffer)) < 0
1feee8
+	      || !__res_binary_hnok (expected_name)
1feee8
+	      || __ns_name_ntop (name_buffer, hname, sizeof (hname)) < 0)
1feee8
 	    {
1feee8
-	      ++had_error;
1feee8
-	      break;
1feee8
+	      *h_errnop = NO_RECOVERY;
1feee8
+	      return NSS_STATUS_UNAVAIL;
1feee8
 	    }
1feee8
-	  if (ttlp != NULL && ttl < *ttlp)
1feee8
-	      *ttlp = ttl;
1feee8
-	  /* bind would put multiple PTR records as aliases, but we don't do
1feee8
-	     that.  */
1feee8
-	  result->h_name = bp;
1feee8
-	  *h_errnop = NETDB_SUCCESS;
1feee8
+	  /* Successful allocation is checked by the caller.  */
1feee8
+	  *hnamep = alloc_buffer_copy_string (abuf, hname);
1feee8
 	  return NSS_STATUS_SUCCESS;
1feee8
-	case T_A:
1feee8
-	case T_AAAA:
1feee8
-	  if (__glibc_unlikely (__strcasecmp (result->h_name, bp) != 0))
1feee8
-	    {
1feee8
-	      cp += n;
1feee8
-	      continue;			/* XXX - had_error++ ? */
1feee8
-	    }
1feee8
-
1feee8
-	  /* Stop parsing at a record whose length is incorrect.  */
1feee8
-	  if (n != rrtype_to_rdata_length (type))
1feee8
-	    {
1feee8
-	      ++had_error;
1feee8
-	      break;
1feee8
-	    }
1feee8
-
1feee8
-	  /* Skip records of the wrong type.  */
1feee8
-	  if (n != result->h_length)
1feee8
-	    {
1feee8
-	      cp += n;
1feee8
-	      continue;
1feee8
-	    }
1feee8
-	  if (!haveanswer)
1feee8
-	    {
1feee8
-	      int nn;
1feee8
-
1feee8
-	      /* We compose a single hostent out of the entire chain of
1feee8
-	         entries, so the TTL of the hostent is essentially the lowest
1feee8
-		 TTL in the chain.  */
1feee8
-	      if (ttlp != NULL && ttl < *ttlp)
1feee8
-		*ttlp = ttl;
1feee8
-	      result->h_name = bp;
1feee8
-	      nn = strlen (bp) + 1;	/* for the \0 */
1feee8
-	      bp += nn;
1feee8
-	      linebuflen -= nn;
1feee8
-	    }
1feee8
-
1feee8
-	  /* Provide sufficient alignment for both address
1feee8
-	     families.  */
1feee8
-	  enum { align = 4 };
1feee8
-	  _Static_assert ((align % __alignof__ (struct in_addr)) == 0,
1feee8
-			  "struct in_addr alignment");
1feee8
-	  _Static_assert ((align % __alignof__ (struct in6_addr)) == 0,
1feee8
-			  "struct in6_addr alignment");
1feee8
-	  {
1feee8
-	    char *new_bp = PTR_ALIGN_UP (bp, align);
1feee8
-	    linebuflen -= new_bp - bp;
1feee8
-	    bp = new_bp;
1feee8
-	  }
1feee8
-
1feee8
-	  if (__glibc_unlikely (n > linebuflen))
1feee8
-	    goto too_small;
1feee8
-	  bp = __mempcpy (*hap++ = bp, cp, n);
1feee8
-	  cp += n;
1feee8
-	  linebuflen -= n;
1feee8
-	  break;
1feee8
-	default:
1feee8
-	  cp += n;
1feee8
-	  continue;			/* XXX - had_error++ ? */
1feee8
 	}
1feee8
-      if (had_error == 0)
1feee8
-	++haveanswer;
1feee8
     }
1feee8
 
1feee8
-  if (haveanswer > 0)
1feee8
-    {
1feee8
-      *ap = NULL;
1feee8
-      *hap = NULL;
1feee8
-
1feee8
-      if (result->h_name == NULL)
1feee8
-	{
1feee8
-	  n = strlen (qname) + 1;	/* For the \0.  */
1feee8
-	  if (n > linebuflen)
1feee8
-	    goto too_small;
1feee8
-	  if (n >= MAXHOSTNAMELEN)
1feee8
-	    goto no_recovery;
1feee8
-	  result->h_name = bp;
1feee8
-	  bp = __mempcpy (bp, qname, n);	/* Cannot overflow.  */
1feee8
-	  linebuflen -= n;
1feee8
-	}
1feee8
+  /* No PTR record found.  */
1feee8
+  if (ttlp != NULL)
1feee8
+    /* No caching of negative responses.  */
1feee8
+    *ttlp = 0;
1feee8
 
1feee8
-      *h_errnop = NETDB_SUCCESS;
1feee8
-      return NSS_STATUS_SUCCESS;
1feee8
-    }
1feee8
- no_recovery:
1feee8
   *h_errnop = NO_RECOVERY;
1feee8
   *errnop = ENOENT;
1feee8
   return NSS_STATUS_TRYAGAIN;