(_nss_dns_gethostbyname2_r): If res_search fails don't rely on errno value.
[kopensolaris-gnu/glibc.git] / resolv / nss_dns / dns-host.c
index 4d46384..c075961 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
 
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
@@ -116,6 +112,12 @@ typedef union querybuf
   u_char buf[MAXPACKET];
 } querybuf;
 
+/* These functions are defined in res_comp.c.  */
+#define NS_MAXCDNAME   255     /* maximum compressed domain name */
+extern int __ns_name_ntop __P ((const u_char *, char *, size_t));
+extern int __ns_name_unpack __P ((const u_char *, const u_char *,
+                                 const u_char *, u_char *, size_t));
+
 
 static enum nss_status getanswer_r (const querybuf *answer, int anslen,
                                    const char *qname, int qtype,
@@ -141,7 +143,7 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
     type = T_AAAA;
     break;
   default:
-    *h_errnop = NETDB_INTERNAL;
+    *h_errnop = NO_DATA;
     *errnop = EAFNOSUPPORT;
     return NSS_STATUS_UNAVAIL;
   }
@@ -161,7 +163,7 @@ _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
   if (n < 0)
     {
       *h_errnop = h_errno;
-      *errnop = errno;
+      *errnop = *h_errnop == TRY_AGAIN ? EAGAIN : ENOENT;
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
@@ -189,7 +191,7 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
 
 
 enum nss_status
-_nss_dns_gethostbyaddr_r (const char *addr, int len, int af,
+_nss_dns_gethostbyaddr_r (const char *addr, size_t len, int af,
                          struct hostent *result, char *buffer, size_t buflen,
                          int *errnop, int *h_errnop)
 {
@@ -205,7 +207,8 @@ _nss_dns_gethostbyaddr_r (const char *addr, int len, int af,
   } *host_data = (struct host_data *) buffer;
   querybuf host_buffer;
   char qbuf[MAXDNAME+1], *qp;
-  int size, n, status;
+  size_t size;
+  int n, status;
 
   if (af == AF_INET6 && len == IN6ADDRSZ &&
       (memcmp (uaddr, mapped, sizeof mapped) == 0
@@ -315,6 +318,16 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
   char tbuf[MAXDNAME];
   const char *tname;
   int (*name_ok) __P ((const char *));
+  u_char packtmp[NS_MAXCDNAME];
+
+  if (linebuflen < 0)
+    {
+      /* The buffer is too small.  */
+    too_small:
+      *errnop = ERANGE;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_TRYAGAIN;
+    }
 
   tname = qname;
   result->h_name = NULL;
@@ -329,6 +342,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       name_ok = res_dnok;
       break;
     default:
+      *errnop = ENOENT;
       return NSS_STATUS_UNAVAIL;  /* XXX should be abort(); */
     }
 
@@ -343,23 +357,27 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
   if (qdcount != 1)
     {
       *h_errnop = NO_RECOVERY;
+      *errnop = ENOENT;
       return NSS_STATUS_UNAVAIL;
     }
 
-  n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
-  if (n < 0 || (*name_ok) (bp) == 0)
+  n = __ns_name_unpack (answer->buf, end_of_message, cp,
+                       packtmp, sizeof packtmp);
+  if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
     {
       if (errno == EMSGSIZE)
-       {
-         /* There is not enough room in the input buffer.  */
-         *errnop = ERANGE;
-         *h_errnop = NETDB_INTERNAL;
-       }
-      else
-       {
-         *errnop = errno;
-         *h_errnop = NO_RECOVERY;
-       }
+       goto too_small;
+
+      n = -1;
+    }
+
+  if (n > 0 && bp[0] == '.')
+    bp[0] = '\0';
+
+  if (n < 0 || (*name_ok) (bp) == 0)
+    {
+      *errnop = errno;
+      *h_errnop = NO_RECOVERY;
       return NSS_STATUS_UNAVAIL;
     }
   cp += n + QFIXEDSZ;
@@ -374,11 +392,14 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       if (n >= MAXHOSTNAMELEN)
        {
          *h_errnop = NO_RECOVERY;
+         *errnop = ENOENT;
          return NSS_STATUS_TRYAGAIN;
        }
       result->h_name = bp;
       bp += n;
       linebuflen -= n;
+      if (linebuflen < 0)
+       goto too_small;
       /* The qname can be abbreviated, but h_name is now absolute. */
       qname = result->h_name;
     }
@@ -396,7 +417,16 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
     {
       int type, class;
 
-      n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+      n = __ns_name_unpack (answer->buf, end_of_message, cp,
+                           packtmp, sizeof packtmp);
+      if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+       {
+         if (errno == EMSGSIZE)
+           goto too_small;
+
+         n = -1;
+       }
+
       if (n < 0 || (*name_ok) (bp) == 0)
        {
          ++had_error;
@@ -405,9 +435,9 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       cp += n;                         /* name */
       type = _getshort (cp);
       cp += INT16SZ;                   /* type */
-      class = _getshort(cp);
+      class = _getshort (cp);
       cp += INT16SZ + INT32SZ;         /* class, TTL */
-      n = _getshort(cp);
+      n = _getshort (cp);
       cp += INT16SZ;                   /* len */
       if (class != C_IN)
        {
@@ -439,13 +469,15 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
          linebuflen -= n;
          /* Get canonical name.  */
          n = strlen (tbuf) + 1;        /* For the \0.  */
-         if ((size_t) n > buflen || n >= MAXHOSTNAMELEN)
+         if (n > linebuflen)
+           goto too_small;
+         if (n >= MAXHOSTNAMELEN)
            {
              ++had_error;
              continue;
            }
-         result->h_name = strcpy (bp, tbuf);   /* Cannot overflow.  */
-         bp += n;
+         result->h_name = bp;
+         bp = __mempcpy (bp, tbuf, n); /* Cannot overflow.  */
          linebuflen -= n;
          continue;
        }
@@ -461,13 +493,15 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
          cp += n;
          /* Get canonical name.  */
          n = strlen (tbuf) + 1;   /* For the \0.  */
-         if ((size_t) n > buflen || n >= MAXHOSTNAMELEN)
+         if (n > linebuflen)
+           goto too_small;
+         if (n >= MAXHOSTNAMELEN)
            {
              ++had_error;
              continue;
            }
-         tname = strcpy (bp, tbuf);    /* Cannot overflow.  */
-         bp += n;
+         tname = bp;
+         bp = __mempcpy (bp, tbuf, n); /* Cannot overflow.  */
          linebuflen -= n;
          continue;
        }
@@ -493,13 +527,23 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       switch (type)
        {
        case T_PTR:
-         if (strcasecmp (tname, bp) != 0)
+         if (__strcasecmp (tname, bp) != 0)
            {
              syslog (LOG_NOTICE | LOG_AUTH, AskedForGot, qname, bp);
              cp += n;
              continue;                 /* XXX - had_error++ ? */
            }
-         n = dn_expand (answer->buf, end_of_message, cp, bp, linebuflen);
+
+         n = __ns_name_unpack (answer->buf, end_of_message, cp,
+                               packtmp, sizeof packtmp);
+         if (n != -1 && __ns_name_ntop (packtmp, bp, linebuflen) == -1)
+           {
+             if (errno == EMSGSIZE)
+               goto too_small;
+
+             n = -1;
+           }
+
          if (n < 0 || res_hnok (bp) == 0)
            {
              ++had_error;
@@ -565,20 +609,17 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
              linebuflen -= nn;
            }
 
+         linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
          bp += sizeof (align) - ((u_long) bp % sizeof (align));
 
-         if (n >= linebuflen)
-           {
-             ++had_error;
-             continue;
-           }
+         if (n > linebuflen)
+           goto too_small;
          if (hap >= &host_data->h_addr_ptrs[MAX_NR_ADDRS-1])
            {
              cp += n;
              continue;
            }
-         memcpy (*hap++ = bp, cp, n);
-         bp += n;
+         bp = __mempcpy (*hap++ = bp, cp, n);
          cp += n;
          linebuflen -= n;
          break;
@@ -606,10 +647,12 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
       if (result->h_name == NULL)
        {
          n = strlen (qname) + 1;       /* For the \0.  */
-         if (n > linebuflen || n >= MAXHOSTNAMELEN)
+         if (n > linebuflen)
+           goto too_small;
+         if (n >= MAXHOSTNAMELEN)
            goto no_recovery;
-         result->h_name = strcpy (bp, qname);  /* Cannot overflow.  */
-         bp += n;
+         result->h_name = bp;
+         bp = __mempcpy (bp, qname, n);        /* Cannot overflow.  */
          linebuflen -= n;
        }
 
@@ -620,5 +663,6 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
     }
  no_recovery:
   *h_errnop = NO_RECOVERY;
+  *errnop = ENOENT;
   return NSS_STATUS_TRYAGAIN;
 }