@@ -52,13 +52,8 @@
#include <arpa/nameser.h>
#include <sys/socket.h>
-typedef union {
- int32_t al;
- char ac;
-} align;
-
static int
-map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
+map_v4v6_hostent (struct hostent *hp, struct alloc_buffer *abuffer)
{
char **ap;
@@ -68,17 +63,15 @@ map_v4v6_hostent (struct hostent *hp, char **bpp, int *lenp)
hp->h_length = IN6ADDRSZ;
for (ap = hp->h_addr_list; *ap; ap++)
{
- int i = sizeof (align) - ((u_long) *bpp % sizeof (align));
-
- if (*lenp < (i + IN6ADDRSZ))
+ struct in6_addr *addr = alloc_buffer_alloc (abuffer, struct in6_addr);
+ if (addr == NULL)
/* Out of memory. */
return 1;
- *bpp += i;
- *lenp -= i;
- map_v4v6_address (*ap, *bpp);
- *ap = *bpp;
- *bpp += IN6ADDRSZ;
- *lenp -= IN6ADDRSZ;
+ addr->s6_addr32[0] = htonl (0);
+ addr->s6_addr32[1] = htonl (0);
+ addr->s6_addr32[2] = htonl (0xffff);
+ memcpy (&addr->s6_addr32[3], *ap, sizeof (addr->s6_addr32[3]));
+ *ap = (char *) addr;
}
return 0;
}
@@ -82,11 +82,12 @@
#include "nsswitch.h"
#include <arpa/nameser.h>
+#include <alloc_buffer.h>
+
#include <resolv/resolv-internal.h>
#include <resolv/resolv_context.h>
/* Get implementations of some internal functions. */
-#include <resolv/mapv4v6addr.h>
#include <resolv/mapv4v6hostent.h>
#define RESOLVSORT
@@ -112,8 +113,9 @@ typedef union querybuf
static enum nss_status getanswer_r (struct resolv_context *ctx,
const querybuf *answer, int anslen,
const char *qname, int qtype,
- struct hostent *result, char *buffer,
- size_t buflen, int *errnop, int *h_errnop,
+ struct hostent *result,
+ struct alloc_buffer *buffer,
+ int *errnop, int *h_errnop,
int map, int32_t *ttlp, char **canonp);
static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
@@ -266,8 +268,9 @@ gethostbyname3_context (struct resolv_context *ctx,
result->h_length = INADDRSZ;
}
+ struct alloc_buffer abuffer = alloc_buffer_create (buffer, buflen);
status = getanswer_r
- (ctx, host_buffer.buf, n, name, type, result, buffer, buflen,
+ (ctx, host_buffer.buf, n, name, type, result, &abuffer,
errnop, h_errnop, map, ttlp, canonp);
if (host_buffer.buf != orig_host_buffer)
free (host_buffer.buf);
@@ -435,13 +438,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
static const u_char v6local[] = { 0,0, 0,1 };
const u_char *uaddr = (const u_char *)addr;
- struct host_data
- {
- char *aliases[MAX_NR_ALIASES];
- unsigned char host_addr[16]; /* IPv4 or IPv6 */
- char *h_addr_ptrs[MAX_NR_ADDRS + 1];
- char linebuffer[0];
- } *host_data = (struct host_data *) buffer;
union
{
querybuf *buf;
@@ -453,19 +449,6 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
int n, status;
int olderr = errno;
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
- buffer += pad;
- buflen = buflen > pad ? buflen - pad : 0;
-
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
- {
- *errnop = ERANGE;
- *h_errnop = NETDB_INTERNAL;
- return NSS_STATUS_TRYAGAIN;
- }
-
- host_data = (struct host_data *) buffer;
-
struct resolv_context *ctx = __resolv_context_get ();
if (ctx == NULL)
{
@@ -545,8 +528,9 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
}
+ struct alloc_buffer abuffer = alloc_buffer_create (buffer, buflen);
status = getanswer_r
- (ctx, host_buffer.buf, n, qbuf, T_PTR, result, buffer, buflen,
+ (ctx, host_buffer.buf, n, qbuf, T_PTR, result, &abuffer,
errnop, h_errnop, 0 /* XXX */, ttlp, NULL);
if (host_buffer.buf != orig_host_buffer)
free (host_buffer.buf);
@@ -558,9 +542,21 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
result->h_addrtype = af;
result->h_length = len;
- memcpy (host_data->host_addr, addr, len);
- host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
- host_data->h_addr_ptrs[1] = NULL;
+ result->h_addr_list = alloc_buffer_alloc_array (&abuffer, char *, 2);
+ if (result->h_addr_list != NULL)
+ {
+ char *host_addr = __alloc_buffer_alloc (&abuffer, len,
+ __alignof (struct in_addr));
+ memcpy (host_addr, addr, len);
+ result->h_addr_list[0] = host_addr;
+ result->h_addr_list[1] = NULL;
+ }
+ if (alloc_buffer_has_failed (&abuffer))
+ {
+ *errnop = ERANGE;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_TRYAGAIN;
+ }
*h_errnop = NETDB_SUCCESS;
__resolv_context_put (ctx);
return NSS_STATUS_SUCCESS;
@@ -626,41 +622,19 @@ addrsort (struct resolv_context *ctx, char **ap, int num)
static enum nss_status
getanswer_r (struct resolv_context *ctx,
const querybuf *answer, int anslen, const char *qname, int qtype,
- struct hostent *result, char *buffer, size_t buflen,
+ struct hostent *result, struct alloc_buffer *buffer,
int *errnop, int *h_errnop, int map, int32_t *ttlp, char **canonp)
{
- struct host_data
- {
- char *aliases[MAX_NR_ALIASES];
- unsigned char host_addr[16]; /* IPv4 or IPv6 */
- char *h_addr_ptrs[0];
- } *host_data;
- int linebuflen;
const HEADER *hp;
const u_char *end_of_message, *cp;
int n, ancount, qdcount;
int haveanswer, had_error;
- char *bp, **ap, **hap;
+ char **ap, **hap;
char tbuf[MAXDNAME];
const char *tname;
int (*name_ok) (const char *);
u_char packtmp[NS_MAXCDNAME];
int have_to_map = 0;
- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct host_data);
- buffer += pad;
- buflen = buflen > pad ? buflen - pad : 0;
- if (__glibc_unlikely (buflen < sizeof (struct host_data)))
- {
- /* The buffer is too small. */
- too_small:
- *errnop = ERANGE;
- *h_errnop = NETDB_INTERNAL;
- return NSS_STATUS_TRYAGAIN;
- }
- host_data = (struct host_data *) buffer;
- linebuflen = buflen - sizeof (struct host_data);
- if (buflen - sizeof (struct host_data) != linebuflen)
- linebuflen = INT_MAX;
tname = qname;
result->h_name = NULL;
@@ -691,10 +665,18 @@ getanswer_r (struct resolv_context *ctx,
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
- if (sizeof (struct host_data) + (ancount + 1) * sizeof (char *) >= buflen)
- goto too_small;
- bp = (char *) &host_data->h_addr_ptrs[ancount + 1];
- linebuflen -= (ancount + 1) * sizeof (char *);
+
+ result->h_aliases = alloc_buffer_alloc_array (buffer, char *,
+ MAX_NR_ALIASES);
+ result->h_addr_list = alloc_buffer_alloc_array (buffer, char *,
+ ancount + 1);
+ if (result->h_addr_list == NULL)
+ {
+ too_small:
+ *errnop = ERANGE;
+ *h_errnop = NETDB_INTERNAL;
+ return NSS_STATUS_TRYAGAIN;
+ }
n = __ns_name_unpack (answer->buf, end_of_message, cp,
packtmp, sizeof packtmp);
@@ -704,13 +686,21 @@ getanswer_r (struct resolv_context *ctx,
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
- if (__ns_name_ntop (packtmp, bp, linebuflen) < 0)
+
+ if (__ns_name_ntop (packtmp, alloc_buffer_next (buffer, char),
+ alloc_buffer_size (buffer)) < 0)
goto too_small;
- if (bp[0] == '.')
- bp[0] = '\0';
+ /* Store the currently processed name in the unallocated tail of the
+ buffer. In subsequent iterations of the loop, the decoded name
+ may be discarded if it is not needed after all, and current_name
+ becomes invalid at this point. */
+ char *current_name = alloc_buffer_next (buffer, char);
- if (__glibc_unlikely (name_ok (bp) == 0))
+ if (current_name[0] == '.')
+ current_name[0] = '\0';
+
+ if (__glibc_unlikely (name_ok (current_name) == 0))
{
errno = EBADMSG;
*errnop = EBADMSG;
@@ -725,28 +715,23 @@ getanswer_r (struct resolv_context *ctx,
* same as the one we sent; this just gets the expanded name
* (i.e., with the succeeding search-domain tacked on).
*/
- n = strlen (bp) + 1; /* for the \0 */
+ n = strlen (current_name) + 1; /* For the '\0'. */
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;
+ result->h_name = current_name;
+ alloc_buffer_alloc_bytes (buffer, n);
/* The qname can be abbreviated, but h_name is now absolute. */
qname = result->h_name;
}
- ap = host_data->aliases;
+ ap = result->h_aliases;
*ap = NULL;
- result->h_aliases = host_data->aliases;
- hap = host_data->h_addr_ptrs;
+ hap = result->h_addr_list;
*hap = NULL;
- result->h_addr_list = host_data->h_addr_ptrs;
haveanswer = 0;
had_error = 0;
@@ -762,10 +747,12 @@ getanswer_r (struct resolv_context *ctx,
continue;
}
- if (__ns_name_ntop (packtmp, bp, linebuflen) < 0)
+ if (__ns_name_ntop (packtmp, alloc_buffer_next (buffer, char),
+ alloc_buffer_size (buffer)) < 0)
goto too_small;
+ current_name = alloc_buffer_next (buffer, char);
- if (__glibc_unlikely ((*name_ok) (bp) == 0))
+ if (__glibc_unlikely ((*name_ok) (current_name) == 0))
{
++had_error;
continue;
@@ -807,7 +794,7 @@ getanswer_r (struct resolv_context *ctx,
if (ttlp != NULL && ttl < *ttlp)
*ttlp = ttl;
- if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
+ if (ap >= &result->h_aliases[MAX_NR_ALIASES - 1])
continue;
n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
if (__glibc_unlikely (n < 0 || (*name_ok) (tbuf) == 0))
@@ -817,27 +804,24 @@ getanswer_r (struct resolv_context *ctx,
}
cp += n;
/* Store alias. */
- *ap++ = bp;
- n = strlen (bp) + 1; /* For the \0. */
+ *ap++ = current_name;
+ n = strlen (current_name) + 1; /* For the \0. */
if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
{
++had_error;
continue;
}
- bp += n;
- linebuflen -= n;
+ alloc_buffer_alloc_bytes (buffer, n);
/* Get canonical name. */
- n = strlen (tbuf) + 1; /* For the \0. */
- if (__glibc_unlikely (n > linebuflen))
+ result->h_name = alloc_buffer_copy_string (buffer, tbuf);
+ current_name = NULL;
+ if (result->h_name == NULL)
goto too_small;
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+ if (strlen (tbuf) >= MAXHOSTNAMELEN)
{
++had_error;
continue;
}
- result->h_name = bp;
- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
- linebuflen -= n;
continue;
}
@@ -855,17 +839,15 @@ getanswer_r (struct resolv_context *ctx,
}
cp += n;
/* Get canonical name. */
- n = strlen (tbuf) + 1; /* For the \0. */
- if (__glibc_unlikely (n > linebuflen))
+ tname = alloc_buffer_copy_string (buffer, tbuf);
+ if (tname == NULL)
goto too_small;
- if (__glibc_unlikely (n >= MAXHOSTNAMELEN))
+ if (strlen (tbuf) >= MAXHOSTNAMELEN)
{
++had_error;
continue;
}
- tname = bp;
- bp = __mempcpy (bp, tbuf, n); /* Cannot overflow. */
- linebuflen -= n;
+ current_name = NULL;
continue;
}
@@ -880,7 +862,8 @@ getanswer_r (struct resolv_context *ctx,
switch (type)
{
case T_PTR:
- if (__glibc_unlikely (strcasecmp (tname, bp) != 0))
+ if (__glibc_unlikely (strcasecmp (tname, current_name)
+ != 0))
{
cp += n;
continue; /* XXX - had_error++ ? */
@@ -893,9 +876,14 @@ getanswer_r (struct resolv_context *ctx,
++had_error;
break;
}
- if (__ns_name_ntop (packtmp, bp, linebuflen) < 0)
+
+ if (__ns_name_ntop (packtmp,
+ alloc_buffer_next (buffer, char),
+ alloc_buffer_size (buffer)) < 0)
goto too_small;
- if (__glibc_unlikely (res_hnok (bp) == 0))
+ current_name = alloc_buffer_next (buffer, char);
+
+ if (__glibc_unlikely (res_hnok (current_name) == 0))
{
++had_error;
break;
@@ -904,12 +892,14 @@ getanswer_r (struct resolv_context *ctx,
*ttlp = ttl;
/* bind would put multiple PTR records as aliases, but we don't do
that. */
- result->h_name = bp;
+ result->h_name = alloc_buffer_next (buffer, char);
+ alloc_buffer_alloc_bytes (buffer, strlen (result->h_name) + 1);
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
case T_A:
case T_AAAA:
- if (__glibc_unlikely (strcasecmp (result->h_name, bp) != 0))
+ if (__glibc_unlikely (strcasecmp (result->h_name, current_name)
+ != 0))
{
cp += n;
continue; /* XXX - had_error++ ? */
@@ -930,29 +920,26 @@ getanswer_r (struct resolv_context *ctx,
}
if (!haveanswer)
{
- int nn;
-
/* We compose a single hostent out of the entire chain of
entries, so the TTL of the hostent is essentially the lowest
TTL in the chain. */
if (ttlp != NULL && ttl < *ttlp)
*ttlp = ttl;
if (canonp != NULL)
- *canonp = bp;
- result->h_name = bp;
- nn = strlen (bp) + 1; /* for the \0 */
- bp += nn;
- linebuflen -= nn;
+ *canonp = alloc_buffer_next (buffer, char);
+ result->h_name = alloc_buffer_next (buffer, char);
+ alloc_buffer_alloc_bytes (buffer, strlen (result->h_name) + 1);
}
- linebuflen -= sizeof (align) - ((u_long) bp % sizeof (align));
- bp += sizeof (align) - ((u_long) bp % sizeof (align));
-
- if (__glibc_unlikely (n > linebuflen))
- goto too_small;
- bp = __mempcpy (*hap++ = bp, cp, n);
- cp += n;
- linebuflen -= n;
+ {
+ void *addr = __alloc_buffer_alloc (buffer, n,
+ __alignof (struct in_addr));
+ if (addr == NULL)
+ goto too_small;
+ memcpy (addr, cp, n);
+ *hap++ = addr;
+ cp += n;
+ }
break;
default:
abort ();
@@ -972,22 +959,19 @@ getanswer_r (struct resolv_context *ctx,
*/
if (haveanswer > 1 && qtype == T_A
&& __resolv_context_sort_count (ctx) > 0)
- addrsort (ctx, host_data->h_addr_ptrs, haveanswer);
+ addrsort (ctx, result->h_addr_list, haveanswer);
if (result->h_name == NULL)
{
- n = strlen (qname) + 1; /* For the \0. */
- if (n > linebuflen)
+ result->h_name = alloc_buffer_copy_string (buffer, qname);
+ if (result->h_name == NULL)
goto too_small;
- if (n >= MAXHOSTNAMELEN)
+ if (strlen (qname) + 1 >= MAXHOSTNAMELEN)
goto no_recovery;
- result->h_name = bp;
- bp = __mempcpy (bp, qname, n); /* Cannot overflow. */
- linebuflen -= n;
}
if (have_to_map)
- if (map_v4v6_hostent (result, &bp, &linebuflen))
+ if (map_v4v6_hostent (result, buffer))
goto too_small;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
@@ -998,7 +982,7 @@ getanswer_r (struct resolv_context *ctx,
/* Special case here: if the resolver sent a result but it only
contains a CNAME while we are looking for a T_A or T_AAAA record,
we fail with NOTFOUND instead of TRYAGAIN. */
- return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
+ return ((qtype == T_A || qtype == T_AAAA) && ap != result->h_aliases
? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
}