Module Name: src Committed By: christos Date: Fri Aug 16 15:27:12 UTC 2013
Modified Files: src/lib/libc/net: gethnamaddr.c getnameinfo.c sethostent.c Added Files: src/lib/libc/net: hostent.h Log Message: Add not advertised reentrant functions: {get,set,end}hostent_r, gethostbyname{,2}_r, gethostbyaddr_r. Make getnameinfo(3) use gethostbyaddr_r(3) so it is re-entrant (ahem __ypdomain). These are not being advertised because there is a bunch of different implementation of them that have a variety of type signatures. If people want to follow someone's implementation, it is now easy. To generate a diff of this commit: cvs rdiff -u -r1.79 -r1.80 src/lib/libc/net/gethnamaddr.c cvs rdiff -u -r1.53 -r1.54 src/lib/libc/net/getnameinfo.c cvs rdiff -u -r0 -r1.1 src/lib/libc/net/hostent.h cvs rdiff -u -r1.17 -r1.18 src/lib/libc/net/sethostent.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/net/gethnamaddr.c diff -u src/lib/libc/net/gethnamaddr.c:1.79 src/lib/libc/net/gethnamaddr.c:1.80 --- src/lib/libc/net/gethnamaddr.c:1.79 Sun Sep 9 12:42:23 2012 +++ src/lib/libc/net/gethnamaddr.c Fri Aug 16 11:27:12 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: gethnamaddr.c,v 1.79 2012/09/09 16:42:23 christos Exp $ */ +/* $NetBSD: gethnamaddr.c,v 1.80 2013/08/16 15:27:12 christos Exp $ */ /* * ++Copyright++ 1985, 1988, 1993 @@ -57,7 +57,7 @@ static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93"; static char rcsid[] = "Id: gethnamaddr.c,v 8.21 1997/06/01 20:34:37 vixie Exp "; #else -__RCSID("$NetBSD: gethnamaddr.c,v 1.79 2012/09/09 16:42:23 christos Exp $"); +__RCSID("$NetBSD: gethnamaddr.c,v 1.80 2013/08/16 15:27:12 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -95,6 +95,8 @@ __RCSID("$NetBSD: gethnamaddr.c,v 1.79 2 #include <rpcsvc/ypclnt.h> #endif +#include "hostent.h" + #if defined(_LIBC) && defined(__weak_alias) __weak_alias(gethostbyaddr,_gethostbyaddr) __weak_alias(gethostbyname,_gethostbyname) @@ -111,31 +113,23 @@ __weak_alias(gethostent,_gethostent) #define MAXADDRS 35 static const char AskedForGot[] = - "gethostby*.getanswer: asked for \"%s\", got \"%s\""; + "gethostby*.getanswer: asked for \"%s\", got \"%s\""; -static char *h_addr_ptrs[MAXADDRS + 1]; #ifdef YP static char *__ypdomain; #endif -static struct hostent host; -static char *host_aliases[MAXALIASES]; -static char hostbuf[8*1024]; -static u_int32_t host_addr[16 / sizeof(u_int32_t)]; /* IPv4 or IPv6 */ -static FILE *hostf = NULL; -static int stayopen = 0; - #define MAXPACKET (64*1024) typedef union { - HEADER hdr; - u_char buf[MAXPACKET]; + HEADER hdr; + u_char buf[MAXPACKET]; } querybuf; typedef union { - int32_t al; - char ac; + int32_t al; + char ac; } align; #ifdef DEBUG @@ -143,33 +137,23 @@ static void debugprintf(const char *, re __attribute__((__format__(__printf__, 1, 3))); #endif static struct hostent *getanswer(const querybuf *, int, const char *, int, - res_state); + res_state, struct hostent *, char *, size_t, int *); static void map_v4v6_address(const char *, char *); static void map_v4v6_hostent(struct hostent *, char **, char *); static void addrsort(char **, int, res_state); -void _sethtent(int); -void _endhtent(void); -struct hostent *_gethtent(void); -void ht_sethostent(int); -void ht_endhostent(void); -struct hostent *ht_gethostbyname(char *); -struct hostent *ht_gethostbyaddr(const char *, int, int); void dns_service(void); #undef dn_skipname int dn_skipname(const u_char *, const u_char *); -int _gethtbyaddr(void *, void *, va_list); -int _gethtbyname(void *, void *, va_list); -struct hostent *_gethtbyname2(const char *, int); -int _dns_gethtbyaddr(void *, void *, va_list); -int _dns_gethtbyname(void *, void *, va_list); + +static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *); + #ifdef YP -struct hostent *_yphostent(char *, int); -int _yp_gethtbyaddr(void *, void *, va_list); -int _yp_gethtbyname(void *, void *, va_list); +static struct hostent *_yp_hostent(char *, int, struct getnamaddr *); #endif -static struct hostent *gethostbyname_internal(const char *, int, res_state); +static struct hostent *gethostbyname_internal(const char *, int, res_state, + struct hostent *, char *, size_t, int *); static const ns_src default_dns_files[] = { { NSSRC_FILES, NS_SUCCESS }, @@ -178,6 +162,33 @@ static const ns_src default_dns_files[] }; +#define ARRAY(dst, anum, ptr, len) \ + do { \ + size_t _len = (anum + 1) * sizeof(*dst); \ + if (_len > len) \ + goto nospc; \ + dst = (void *)ptr; \ + ptr += _len; \ + len -= _len; \ + } while (/*CONSTCOND*/0) + +#define COPY(dst, src, slen, ptr, len) \ + do { \ + if ((size_t)slen > len) \ + goto nospc; \ + memcpy(ptr, src, (size_t)slen); \ + dst = ptr; \ + ptr += slen; \ + len -= slen; \ + } while (/* CONSTCOND */0) + +#define SCOPY(dst, src, ptr, len) \ + do { \ + size_t _len = strlen(src) + 1; \ + COPY(dst, src, _len, ptr, len); \ + } while (/* CONSTCOND */0) + + #ifdef DEBUG static void debugprintf(const char *msg, res_state res, ...) @@ -218,17 +229,20 @@ debugprintf(const char *msg, res_state r static struct hostent * getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, - res_state res) + res_state res, struct hostent *hent, char *buf, size_t buflen, int *he) { const HEADER *hp; const u_char *cp; int n; + size_t qlen; const u_char *eom, *erdata; char *bp, **ap, **hap, *ep; int type, class, ancount, qdcount; int haveanswer, had_error; int toobig = 0; char tbuf[MAXDNAME]; + char *aliases[MAXALIASES]; + char *addr_ptrs[MAXADDRS + 1]; const char *tname; int (*name_ok)(const char *); @@ -236,7 +250,7 @@ getanswer(const querybuf *answer, int an _DIAGASSERT(qname != NULL); tname = qname; - host.h_name = NULL; + hent->h_name = NULL; eom = answer->buf + anslen; switch (qtype) { case T_A: @@ -255,19 +269,17 @@ getanswer(const querybuf *answer, int an hp = &answer->hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); - bp = hostbuf; - ep = hostbuf + sizeof hostbuf; + bp = buf; + ep = buf + buflen; cp = answer->buf; BOUNDED_INCR(HFIXEDSZ); - if (qdcount != 1) { - h_errno = NO_RECOVERY; - return NULL; - } + if (qdcount != 1) + goto no_recovery; + n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp)); - if ((n < 0) || !maybe_ok(res, bp, name_ok)) { - h_errno = NO_RECOVERY; - return NULL; - } + if ((n < 0) || !maybe_ok(res, bp, name_ok)) + goto no_recovery; + BOUNDED_INCR(n + QFIXEDSZ); if (qtype == T_A || qtype == T_AAAA) { /* res_send() has already verified that the query name is the @@ -275,21 +287,17 @@ getanswer(const querybuf *answer, int an * (i.e., with the succeeding search-domain tacked on). */ n = (int)strlen(bp) + 1; /* for the \0 */ - if (n >= MAXHOSTNAMELEN) { - h_errno = NO_RECOVERY; - return NULL; - } - host.h_name = bp; + if (n >= MAXHOSTNAMELEN) + goto no_recovery; + hent->h_name = bp; bp += n; /* The qname can be abbreviated, but h_name is now absolute. */ - qname = host.h_name; + qname = hent->h_name; } - ap = host_aliases; + hent->h_aliases = ap = aliases; + hent->h_addr_list = hap = addr_ptrs; *ap = NULL; - host.h_aliases = host_aliases; - hap = h_addr_ptrs; *hap = NULL; - host.h_addr_list = h_addr_ptrs; haveanswer = 0; had_error = 0; while (ancount-- > 0 && cp < eom && !had_error) { @@ -314,18 +322,17 @@ getanswer(const querybuf *answer, int an continue; /* XXX - had_error++ ? */ } if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { - if (ap >= &host_aliases[MAXALIASES-1]) + if (ap >= &aliases[MAXALIASES-1]) continue; - n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf); + n = dn_expand(answer->buf, eom, cp, tbuf, + (int)sizeof tbuf); if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) { had_error++; continue; } cp += n; - if (cp != erdata) { - h_errno = NO_RECOVERY; - return NULL; - } + if (cp != erdata) + goto no_recovery; /* Store alias. */ *ap++ = bp; n = (int)strlen(bp) + 1; /* for the \0 */ @@ -341,21 +348,20 @@ getanswer(const querybuf *answer, int an continue; } strlcpy(bp, tbuf, (size_t)(ep - bp)); - host.h_name = bp; + hent->h_name = bp; bp += n; continue; } if (qtype == T_PTR && type == T_CNAME) { - n = dn_expand(answer->buf, eom, cp, tbuf, (int)sizeof tbuf); + n = dn_expand(answer->buf, eom, cp, tbuf, + (int)sizeof tbuf); if (n < 0 || !maybe_dnok(res, tbuf)) { had_error++; continue; } cp += n; - if (cp != erdata) { - h_errno = NO_RECOVERY; - return NULL; - } + if (cp != erdata) + goto no_recovery; /* Get canonical name. */ n = (int)strlen(tbuf) + 1; /* for the \0 */ if (n > ep - bp || n >= MAXHOSTNAMELEN) { @@ -391,13 +397,11 @@ getanswer(const querybuf *answer, int an } #if MULTI_PTRS_ARE_ALIASES cp += n; - if (cp != erdata) { - h_errno = NO_RECOVERY; - return NULL; - } + if (cp != erdata) + goto no_recovery; if (!haveanswer) - host.h_name = bp; - else if (ap < &host_aliases[MAXALIASES-1]) + hent->h_name = bp; + else if (ap < &aliases[MAXALIASES-1]) *ap++ = bp; else n = -1; @@ -411,7 +415,7 @@ getanswer(const querybuf *answer, int an } break; #else - host.h_name = bp; + hent->h_name = bp; if (res->options & RES_USE_INET6) { n = strlen(bp) + 1; /* for the \0 */ if (n >= MAXHOSTNAMELEN) { @@ -419,26 +423,25 @@ getanswer(const querybuf *answer, int an break; } bp += n; - map_v4v6_hostent(&host, &bp, ep); + map_v4v6_hostent(hent, &bp, ep); } - h_errno = NETDB_SUCCESS; - return &host; + goto success; #endif case T_A: case T_AAAA: - if (strcasecmp(host.h_name, bp) != 0) { + if (strcasecmp(hent->h_name, bp) != 0) { syslog(LOG_NOTICE|LOG_AUTH, - AskedForGot, host.h_name, bp); + AskedForGot, hent->h_name, bp); cp += n; continue; /* XXX - had_error++ ? */ } - if (n != host.h_length) { + if (n != hent->h_length) { cp += n; continue; } if (type == T_AAAA) { struct in6_addr in6; - memcpy(&in6, cp, IN6ADDRSZ); + memcpy(&in6, cp, NS_IN6ADDRSZ); if (IN6_IS_ADDR_V4MAPPED(&in6)) { cp += n; continue; @@ -447,7 +450,7 @@ getanswer(const querybuf *answer, int an if (!haveanswer) { int nn; - host.h_name = bp; + hent->h_name = bp; nn = (int)strlen(bp) + 1; /* for the \0 */ bp += nn; } @@ -455,12 +458,12 @@ getanswer(const querybuf *answer, int an bp += sizeof(align) - (size_t)((u_long)bp % sizeof(align)); - if (bp + n >= &hostbuf[sizeof hostbuf]) { + if (bp + n >= ep) { debugprintf("size (%d) too big\n", res, n); had_error++; continue; } - if (hap >= &h_addr_ptrs[MAXADDRS-1]) { + if (hap >= &addr_ptrs[MAXADDRS - 1]) { if (!toobig++) { debugprintf("Too many addresses (%d)\n", res, MAXADDRS); @@ -471,10 +474,8 @@ getanswer(const querybuf *answer, int an (void)memcpy(*hap++ = bp, cp, (size_t)n); bp += n; cp += n; - if (cp != erdata) { - h_errno = NO_RECOVERY; - return NULL; - } + if (cp != erdata) + goto no_recovery; break; default: abort(); @@ -491,70 +492,96 @@ getanswer(const querybuf *answer, int an * address in that case, not some random one */ if (res->nsort && haveanswer > 1 && qtype == T_A) - addrsort(h_addr_ptrs, haveanswer, res); - if (!host.h_name) { + addrsort(addr_ptrs, haveanswer, res); + if (!hent->h_name) { n = (int)strlen(qname) + 1; /* for the \0 */ if (n > ep - bp || n >= MAXHOSTNAMELEN) goto no_recovery; strlcpy(bp, qname, (size_t)(ep - bp)); - host.h_name = bp; + hent->h_name = bp; bp += n; } if (res->options & RES_USE_INET6) - map_v4v6_hostent(&host, &bp, ep); - h_errno = NETDB_SUCCESS; - return &host; + map_v4v6_hostent(hent, &bp, ep); + goto success; } - no_recovery: - h_errno = NO_RECOVERY; +no_recovery: + *he = NO_RECOVERY; + return NULL; +success: + bp = (char *)ALIGN(bp); + n = (int)(ap - aliases); + qlen = (n + 1) * sizeof(*hent->h_aliases); + if ((size_t)(ep - bp) < qlen) + goto nospc; + hent->h_aliases = (void *)bp; + memcpy(bp, aliases, qlen); + + bp += qlen; + n = (int)(hap - addr_ptrs); + qlen = (n + 1) * sizeof(*hent->h_addr_list); + if ((size_t)(ep - bp) < qlen) + goto nospc; + hent->h_addr_list = (void *)bp; + memcpy(bp, addr_ptrs, qlen); + *he = NETDB_SUCCESS; + return hent; +nospc: + errno = ENOSPC; + *he = NETDB_INTERNAL; return NULL; } struct hostent * -gethostbyname(const char *name) +gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen, + int *he) { - struct hostent *hp; res_state res = __res_get_state(); - if (res == NULL) + if (res == NULL) { + *he = NETDB_INTERNAL; return NULL; + } _DIAGASSERT(name != NULL); if (res->options & RES_USE_INET6) { - hp = gethostbyname_internal(name, AF_INET6, res); + hp = gethostbyname_internal(name, AF_INET6, res, hp, buf, + buflen, he); if (hp) { __res_put_state(res); return hp; } } - hp = gethostbyname_internal(name, AF_INET, res); + hp = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, he); __res_put_state(res); return hp; } struct hostent * -gethostbyname2(const char *name, int af) +gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf, + size_t buflen, int *he) { - struct hostent *hp; res_state res = __res_get_state(); - if (res == NULL) + if (res == NULL) { + *he = NETDB_INTERNAL; return NULL; - hp = gethostbyname_internal(name, af, res); + } + hp = gethostbyname_internal(name, af, res, hp, buf, buflen, he); __res_put_state(res); return hp; } static struct hostent * -gethostbyname_internal(const char *name, int af, res_state res) +gethostbyname_internal(const char *name, int af, res_state res, + struct hostent *hp, char *buf, size_t buflen, int *he) { const char *cp; - char *bp, *ep; - int size; - struct hostent *hp; + struct getnamaddr info; + size_t size; static const ns_dtab dtab[] = { - NS_FILES_CB(_gethtbyname, NULL) + NS_FILES_CB(_hf_gethtbyname, NULL) { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */ NS_NIS_CB(_yp_gethtbyname, NULL) NS_NULL_CB @@ -564,19 +591,21 @@ gethostbyname_internal(const char *name, switch (af) { case AF_INET: - size = INADDRSZ; + size = NS_INADDRSZ; break; case AF_INET6: - size = IN6ADDRSZ; + size = NS_IN6ADDRSZ; break; default: - h_errno = NETDB_INTERNAL; + *he = NETDB_INTERNAL; errno = EAFNOSUPPORT; return NULL; } + if (buflen < size) + goto nospc; - host.h_addrtype = af; - host.h_length = size; + hp->h_addrtype = af; + hp->h_length = (int)size; /* * if there aren't any dots, it could be a user-level alias. @@ -600,25 +629,7 @@ gethostbyname_internal(const char *name, * Fake up a hostent as if we'd actually * done a lookup. */ - if (inet_pton(af, name, - (char *)(void *)host_addr) <= 0) { - h_errno = HOST_NOT_FOUND; - return NULL; - } - strncpy(hostbuf, name, MAXDNAME); - hostbuf[MAXDNAME] = '\0'; - bp = hostbuf + MAXDNAME; - ep = hostbuf + sizeof hostbuf; - host.h_name = hostbuf; - host.h_aliases = host_aliases; - host_aliases[0] = NULL; - h_addr_ptrs[0] = (char *)(void *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; - if (res->options & RES_USE_INET6) - map_v4v6_hostent(&host, &bp, ep); - h_errno = NETDB_SUCCESS; - return &host; + goto fake; } if (!isdigit((u_char) *cp) && *cp != '.') break; @@ -634,46 +645,58 @@ gethostbyname_internal(const char *name, * Fake up a hostent as if we'd actually * done a lookup. */ - if (inet_pton(af, name, - (char *)(void *)host_addr) <= 0) { - h_errno = HOST_NOT_FOUND; - return NULL; - } - strncpy(hostbuf, name, MAXDNAME); - hostbuf[MAXDNAME] = '\0'; - bp = hostbuf + MAXDNAME; - ep = hostbuf + sizeof hostbuf; - host.h_name = hostbuf; - host.h_aliases = host_aliases; - host_aliases[0] = NULL; - h_addr_ptrs[0] = (char *)(void *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; - h_errno = NETDB_SUCCESS; - return &host; + goto fake; } if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.') break; } - hp = NULL; - h_errno = NETDB_INTERNAL; - if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname", + *he = NETDB_INTERNAL; + info.hp = hp; + info.buf = buf; + info.buflen = buflen; + info.he = he; + if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname", default_dns_files, name, strlen(name), af) != NS_SUCCESS) return NULL; - h_errno = NETDB_SUCCESS; + *he = NETDB_SUCCESS; + return hp; +nospc: + *he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; +fake: + ARRAY(hp->h_addr_list, 1, buf, buflen); + ARRAY(hp->h_aliases, 0, buf, buflen); + + hp->h_aliases[0] = NULL; + if (size > buflen) + goto nospc; + + if (inet_pton(af, name, buf) <= 0) { + *he = HOST_NOT_FOUND; + return NULL; + } + hp->h_addr_list[0] = buf; + hp->h_addr_list[1] = NULL; + buf += size; + buflen -= size; + SCOPY(hp->h_name, name, buf, buflen); + if (res->options & RES_USE_INET6) + map_v4v6_hostent(hp, &buf, buf + buflen); + *he = NETDB_SUCCESS; return hp; } struct hostent * -gethostbyaddr(const char *addr, /* XXX should have been def'd as u_char! */ - socklen_t len, int af) +gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, + char *buf, size_t buflen, int *he) { const u_char *uaddr = (const u_char *)addr; socklen_t size; - struct hostent *hp; + struct getnamaddr info; static const ns_dtab dtab[] = { - NS_FILES_CB(_gethtbyaddr, NULL) + NS_FILES_CB(_hf_gethtbyaddr, NULL) { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */ NS_NIS_CB(_yp_gethtbyaddr, NULL) NS_NULL_CB @@ -681,293 +704,338 @@ gethostbyaddr(const char *addr, /* XXX s _DIAGASSERT(addr != NULL); - if (af == AF_INET6 && len == IN6ADDRSZ && - (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) || - IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) { - h_errno = HOST_NOT_FOUND; + if (af == AF_INET6 && len == NS_IN6ADDRSZ && + (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) || + IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) { + *he = HOST_NOT_FOUND; return NULL; } - if (af == AF_INET6 && len == IN6ADDRSZ && - (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) || - IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) { + if (af == AF_INET6 && len == NS_IN6ADDRSZ && + (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) || + IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) { /* Unmap. */ - addr += IN6ADDRSZ - INADDRSZ; - uaddr += IN6ADDRSZ - INADDRSZ; + uaddr += NS_IN6ADDRSZ - NS_INADDRSZ; + addr = uaddr; af = AF_INET; - len = INADDRSZ; + len = NS_INADDRSZ; } switch (af) { case AF_INET: - size = INADDRSZ; + size = NS_INADDRSZ; break; case AF_INET6: - size = IN6ADDRSZ; + size = NS_IN6ADDRSZ; break; default: errno = EAFNOSUPPORT; - h_errno = NETDB_INTERNAL; + *he = NETDB_INTERNAL; return NULL; } if (size != len) { errno = EINVAL; - h_errno = NETDB_INTERNAL; + *he = NETDB_INTERNAL; return NULL; } - hp = NULL; - h_errno = NETDB_INTERNAL; - if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr", + info.hp = hp; + info.buf = buf; + info.buflen = buflen; + info.he = he; + *he = NETDB_INTERNAL; + if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr", default_dns_files, uaddr, len, af) != NS_SUCCESS) return NULL; - h_errno = NETDB_SUCCESS; + *he = NETDB_SUCCESS; return hp; } +static const char *_h_hosts = _PATH_HOSTS; + +void +_hf_sethostsfile(const char *f) { + _h_hosts = f; +} + void -_sethtent(int f) +sethostent_r(FILE **hf) { - if (!hostf) - hostf = fopen(_PATH_HOSTS, "re"); + if (!*hf) + *hf = fopen(_h_hosts, "re"); else - rewind(hostf); - stayopen = f; + rewind(*hf); } void -_endhtent(void) +endhostent_r(FILE **hf) { - if (hostf && !stayopen) { - (void) fclose(hostf); - hostf = NULL; + if (*hf) { + (void)fclose(*hf); + *hf = NULL; } } struct hostent * -_gethtent(void) +gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he) { - char *p; + char *p, *name; char *cp, **q; int af, len; + size_t llen, anum; + char *aliases[MAXALIASES]; + struct in6_addr host_addr; - if (!hostf && !(hostf = fopen(_PATH_HOSTS, "re"))) { - h_errno = NETDB_INTERNAL; + if (hf == NULL) { + *he = NETDB_INTERNAL; + errno = EINVAL; return NULL; } again: - if (!(p = fgets(hostbuf, (int)sizeof hostbuf, hostf))) { - h_errno = HOST_NOT_FOUND; + if ((p = fgetln(hf, &llen)) == NULL) { + *he = HOST_NOT_FOUND; return NULL; } + if (llen < 1) + goto again; if (*p == '#') goto again; + p[llen] = '\0'; if (!(cp = strpbrk(p, "#\n"))) goto again; *cp = '\0'; if (!(cp = strpbrk(p, " \t"))) goto again; *cp++ = '\0'; - if (inet_pton(AF_INET6, p, (char *)(void *)host_addr) > 0) { + if (inet_pton(AF_INET6, p, &host_addr) > 0) { af = AF_INET6; - len = IN6ADDRSZ; - } else if (inet_pton(AF_INET, p, (char *)(void *)host_addr) > 0) { + len = NS_IN6ADDRSZ; + } else if (inet_pton(AF_INET, p, &host_addr) > 0) { res_state res = __res_get_state(); if (res == NULL) return NULL; if (res->options & RES_USE_INET6) { - map_v4v6_address((char *)(void *)host_addr, - (char *)(void *)host_addr); + map_v4v6_address(buf, buf); af = AF_INET6; - len = IN6ADDRSZ; + len = NS_IN6ADDRSZ; } else { af = AF_INET; - len = INADDRSZ; + len = NS_INADDRSZ; } __res_put_state(res); } else { goto again; } /* if this is not something we're looking for, skip it. */ - if (host.h_addrtype != 0 && host.h_addrtype != af) + if (hent->h_addrtype != 0 && hent->h_addrtype != af) goto again; - if (host.h_length != 0 && host.h_length != len) + if (hent->h_length != 0 && hent->h_length != len) goto again; - h_addr_ptrs[0] = (char *)(void *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; - host.h_length = len; - host.h_addrtype = af; + while (*cp == ' ' || *cp == '\t') cp++; - host.h_name = cp; - q = host.h_aliases = host_aliases; - if ((cp = strpbrk(cp, " \t")) != NULL) + if ((cp = strpbrk(name = cp, " \t")) != NULL) *cp++ = '\0'; + q = aliases; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } - if (q < &host_aliases[MAXALIASES - 1]) - *q++ = cp; + if (q >= &aliases[__arraycount(aliases)]) + goto nospc; + *q++ = cp; if ((cp = strpbrk(cp, " \t")) != NULL) *cp++ = '\0'; } - *q = NULL; - h_errno = NETDB_SUCCESS; - return &host; + hent->h_length = len; + hent->h_addrtype = af; + ARRAY(hent->h_addr_list, 1, buf, buflen); + anum = (size_t)(q - aliases); + ARRAY(hent->h_aliases, anum, buf, buflen); + COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf, buflen); + hent->h_addr_list[1] = NULL; + + SCOPY(hent->h_name, name, buf, buflen); + for (size_t i = 0; i < anum; i++) + SCOPY(hent->h_aliases[i], aliases[i], buf, buflen); + hent->h_aliases[anum] = NULL; + + *he = NETDB_SUCCESS; + return hent; +nospc: + errno = ENOSPC; + *he = NETDB_INTERNAL; + return NULL; } /*ARGSUSED*/ int -_gethtbyname(void *rv, void *cb_data, va_list ap) +_hf_gethtbyname(void *rv, void *cb_data, va_list ap) { struct hostent *hp; const char *name; int af; + struct getnamaddr *info = rv; _DIAGASSERT(rv != NULL); name = va_arg(ap, char *); - /* NOSTRICT skip len */(void)va_arg(ap, int); + /* NOSTRICT skip string len */(void)va_arg(ap, int); af = va_arg(ap, int); - hp = NULL; #if 0 { res_state res = __res_get_state(); if (res == NULL) return NS_NOTFOUND; if (res->options & RES_USE_INET6) - hp = _gethtbyname2(name, AF_INET6); - if (hp==NULL) - hp = _gethtbyname2(name, AF_INET); + hp = _hf_gethtbyname2(name, AF_INET6, info); + else + hp = NULL; + if (hp == NULL) + hp = _hf_gethtbyname2(name, AF_INET, info); __res_put_state(res); } #else - hp = _gethtbyname2(name, af); + hp = _hf_gethtbyname2(name, af, info); #endif - *((struct hostent **)rv) = hp; if (hp == NULL) { - h_errno = HOST_NOT_FOUND; + *info->he = HOST_NOT_FOUND; return NS_NOTFOUND; } return NS_SUCCESS; } -struct hostent * -_gethtbyname2(const char *name, int af) +static struct hostent * +_hf_gethtbyname2(const char *name, int af, struct getnamaddr *info) { - struct hostent *p; - char *tmpbuf, *ptr, **cp; - int num; - size_t len; + struct hostent *hp, hent; + char *buf, *ptr; + size_t len, anum, num, i; + FILE *hf; + char *aliases[MAXALIASES]; + char *addr_ptrs[MAXADDRS + 1]; _DIAGASSERT(name != NULL); - _sethtent(stayopen); - ptr = tmpbuf = NULL; - num = 0; - while ((p = _gethtent()) != NULL && num < MAXADDRS) { - if (p->h_addrtype != af) - continue; - if (strcasecmp(p->h_name, name) != 0) { - for (cp = p->h_aliases; *cp != NULL; cp++) + hf = NULL; + sethostent_r(&hf); + if (hf == NULL) { + errno = EINVAL; + *info->he = NETDB_INTERNAL; + return NULL; + } + + if ((ptr = buf = malloc(len = info->buflen)) == NULL) { + *info->he = NETDB_INTERNAL; + return NULL; + } + + anum = 0; /* XXX: gcc */ + hent.h_name = NULL; /* XXX: gcc */ + hent.h_addrtype = 0; /* XXX: gcc */ + hent.h_length = 0; /* XXX: gcc */ + + for (num = 0; num < MAXADDRS;) { + info->hp->h_addrtype = af; + info->hp->h_length = 0; + + hp = gethostent_r(hf, info->hp, info->buf, info->buflen, + info->he); + if (hp == NULL) + break; + + if (strcasecmp(hp->h_name, name) != 0) { + char **cp; + for (cp = hp->h_aliases; *cp != NULL; cp++) if (strcasecmp(*cp, name) == 0) break; if (*cp == NULL) continue; } if (num == 0) { - size_t bufsize; - char *src; + hent.h_addrtype = af = hp->h_addrtype; + hent.h_length = hp->h_length; - bufsize = strlen(p->h_name) + 2 + - MAXADDRS * p->h_length + - ALIGNBYTES; - for (cp = p->h_aliases; *cp != NULL; cp++) - bufsize += strlen(*cp) + 1; - - if ((tmpbuf = malloc(bufsize)) == NULL) { - h_errno = NETDB_INTERNAL; - return NULL; - } - - ptr = tmpbuf; - src = p->h_name; - while ((*ptr++ = *src++) != '\0'); - for (cp = p->h_aliases; *cp != NULL; cp++) { - src = *cp; - while ((*ptr++ = *src++) != '\0'); - } - *ptr++ = '\0'; - - ptr = (char *)(void *)ALIGN(ptr); - } - - (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length); - ptr += p->h_length; + SCOPY(hent.h_name, hp->h_name, ptr, len); + for (anum = 0; hp->h_aliases[anum]; anum++) { + if (anum >= __arraycount(aliases)) + goto nospc; + SCOPY(aliases[anum], hp->h_aliases[anum], + ptr, len); + } + ptr = (void *)ALIGN(ptr); + if ((size_t)(ptr - buf) >= info->buflen) + goto nospc; + } + + if (num >= __arraycount(addr_ptrs)) + goto nospc; + COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr, + len); num++; } - _endhtent(); - if (num == 0) return NULL; + endhostent_r(&hf); - len = ptr - tmpbuf; - if (len > (sizeof(hostbuf) - ALIGNBYTES)) { - free(tmpbuf); - errno = ENOSPC; - h_errno = NETDB_INTERNAL; + if (num == 0) { + *info->he = HOST_NOT_FOUND; return NULL; } - ptr = memcpy((void *)ALIGN(hostbuf), tmpbuf, len); - free(tmpbuf); - host.h_name = ptr; - while (*ptr++); + hp = info->hp; + ptr = info->buf; + len = info->buflen; - cp = host_aliases; - while (*ptr) { - *cp++ = ptr; - while (*ptr++); - } - ptr++; - *cp = NULL; + hp->h_addrtype = hent.h_addrtype; + hp->h_length = hent.h_length; - ptr = (char *)(void *)ALIGN(ptr); - cp = h_addr_ptrs; - while (num--) { - *cp++ = ptr; - ptr += host.h_length; - } - *cp = NULL; + ARRAY(hp->h_aliases, anum, ptr, len); + ARRAY(hp->h_addr_list, num, ptr, len); + + for (i = 0; i < num; i++) + COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr, len); + hp->h_addr_list[num] = NULL; + + SCOPY(hp->h_name, hent.h_name, ptr, len); - return &host; + for (i = 0; i < anum; i++) + SCOPY(hp->h_aliases[i], aliases[i], ptr, len); + hp->h_aliases[anum] = NULL; + + return hp; +nospc: + *info->he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; } /*ARGSUSED*/ int -_gethtbyaddr(void *rv, void *cb_data, va_list ap) +_hf_gethtbyaddr(void *rv, void *cb_data, va_list ap) { - struct hostent *p; + struct hostent *hp; const unsigned char *addr; - int len, af; + struct getnamaddr *info = rv; + FILE *hf; _DIAGASSERT(rv != NULL); addr = va_arg(ap, unsigned char *); - len = va_arg(ap, int); - af = va_arg(ap, int); + info->hp->h_length = va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); - host.h_length = len; - host.h_addrtype = af; - - _sethtent(stayopen); - while ((p = _gethtent()) != NULL) - if (p->h_addrtype == af && !memcmp(p->h_addr, addr, - (size_t)len)) + hf = NULL; + sethostent_r(&hf); + if (hf == NULL) { + *info->he = NETDB_INTERNAL; + return NS_UNAVAIL; + } + while ((hp = gethostent_r(hf, info->hp, info->buf, info->buflen, + info->he)) != NULL) + if (!memcmp(hp->h_addr_list[0], addr, hp->h_length)) break; - _endhtent(); - *((struct hostent **)rv) = p; - if (p==NULL) { - h_errno = HOST_NOT_FOUND; + endhostent_r(&hf); + + if (hp == NULL) { + *info->he = HOST_NOT_FOUND; return NS_NOTFOUND; } return NS_SUCCESS; @@ -977,21 +1045,21 @@ static void map_v4v6_address(const char *src, char *dst) { u_char *p = (u_char *)dst; - char tmp[INADDRSZ]; + char tmp[NS_INADDRSZ]; int i; _DIAGASSERT(src != NULL); _DIAGASSERT(dst != NULL); /* Stash a temporary copy so our caller can update in place. */ - (void)memcpy(tmp, src, INADDRSZ); + (void)memcpy(tmp, src, NS_INADDRSZ); /* Mark this ipv6 addr as a mapped ipv4. */ for (i = 0; i < 10; i++) *p++ = 0x00; *p++ = 0xff; *p++ = 0xff; /* Retrieve the saved copy and we're done. */ - (void)memcpy((void *)p, tmp, INADDRSZ); + (void)memcpy(p, tmp, NS_INADDRSZ); } static void @@ -1003,15 +1071,15 @@ map_v4v6_hostent(struct hostent *hp, cha _DIAGASSERT(bpp != NULL); _DIAGASSERT(ep != NULL); - if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ) + if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ) return; hp->h_addrtype = AF_INET6; - hp->h_length = IN6ADDRSZ; + hp->h_length = NS_IN6ADDRSZ; for (ap = hp->h_addr_list; *ap; ap++) { int i = (int)(sizeof(align) - (size_t)((u_long)*bpp % sizeof(align))); - if (ep - *bpp < (i + IN6ADDRSZ)) { + if (ep - *bpp < (i + NS_IN6ADDRSZ)) { /* Out of memory. Truncate address list here. XXX */ *ap = NULL; return; @@ -1019,7 +1087,7 @@ map_v4v6_hostent(struct hostent *hp, cha *bpp += i; map_v4v6_address(*ap, *bpp); *ap = *bpp; - *bpp += IN6ADDRSZ; + *bpp += NS_IN6ADDRSZ; } } @@ -1066,13 +1134,6 @@ addrsort(char **ap, int num, res_state r } } -struct hostent * -gethostent(void) -{ - host.h_addrtype = 0; - host.h_length = 0; - return _gethtent(); -} /*ARGSUSED*/ int @@ -1082,20 +1143,22 @@ _dns_gethtbyname(void *rv, void *cb_data int n, type; struct hostent *hp; const char *name; - int af; res_state res; + struct getnamaddr *info = rv; _DIAGASSERT(rv != NULL); name = va_arg(ap, char *); - /* NOSTRICT skip len */(void)va_arg(ap, int); - af = va_arg(ap, int); + /* NOSTRICT skip string len */(void)va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); - switch (af) { + switch (info->hp->h_addrtype) { case AF_INET: + info->hp->h_length = NS_INADDRSZ; type = T_A; break; case AF_INET6: + info->hp->h_length = NS_IN6ADDRSZ; type = T_AAAA; break; default: @@ -1103,7 +1166,7 @@ _dns_gethtbyname(void *rv, void *cb_data } buf = malloc(sizeof(*buf)); if (buf == NULL) { - h_errno = NETDB_INTERNAL; + *info->he = NETDB_INTERNAL; return NS_NOTFOUND; } res = __res_get_state(); @@ -1118,7 +1181,8 @@ _dns_gethtbyname(void *rv, void *cb_data __res_put_state(res); return NS_NOTFOUND; } - hp = getanswer(buf, n, name, type, res); + hp = getanswer(buf, n, name, type, res, info->hp, info->buf, + info->buflen, info->he); free(buf); __res_put_state(res); if (hp == NULL) @@ -1130,7 +1194,6 @@ _dns_gethtbyname(void *rv, void *cb_data default: return NS_UNAVAIL; } - *((struct hostent **)rv) = hp; return NS_SUCCESS; } @@ -1143,16 +1206,19 @@ _dns_gethtbyaddr(void *rv, void *cb_data querybuf *buf; struct hostent *hp; const unsigned char *uaddr; - int len, af, advance; + int advance; res_state res; + char *bf; + size_t blen; + struct getnamaddr *info = rv; _DIAGASSERT(rv != NULL); uaddr = va_arg(ap, unsigned char *); - len = va_arg(ap, int); - af = va_arg(ap, int); + info->hp->h_length = va_arg(ap, int); + info->hp->h_addrtype = va_arg(ap, int); - switch (af) { + switch (info->hp->h_addrtype) { case AF_INET: (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa", (uaddr[3] & 0xff), (uaddr[2] & 0xff), @@ -1162,29 +1228,29 @@ _dns_gethtbyaddr(void *rv, void *cb_data case AF_INET6: qp = qbuf; ep = qbuf + sizeof(qbuf) - 1; - for (n = IN6ADDRSZ - 1; n >= 0; n--) { + for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) { advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.", uaddr[n] & 0xf, ((unsigned int)uaddr[n] >> 4) & 0xf); if (advance > 0 && qp + advance < ep) qp += advance; else { - h_errno = NETDB_INTERNAL; + *info->he = NETDB_INTERNAL; return NS_NOTFOUND; } } if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) { - h_errno = NETDB_INTERNAL; + *info->he = NETDB_INTERNAL; return NS_NOTFOUND; } break; default: - abort(); + return NS_UNAVAIL; } buf = malloc(sizeof(*buf)); if (buf == NULL) { - h_errno = NETDB_INTERNAL; + *info->he = NETDB_INTERNAL; return NS_NOTFOUND; } res = __res_get_state(); @@ -1199,11 +1265,12 @@ _dns_gethtbyaddr(void *rv, void *cb_data __res_put_state(res); return NS_NOTFOUND; } - hp = getanswer(buf, n, qbuf, T_PTR, res); + hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf, + info->buflen, info->he); free(buf); if (hp == NULL) { __res_put_state(res); - switch (h_errno) { + switch (*info->he) { case HOST_NOT_FOUND: return NS_NOTFOUND; case TRY_AGAIN: @@ -1212,62 +1279,65 @@ _dns_gethtbyaddr(void *rv, void *cb_data return NS_UNAVAIL; } } - hp->h_addrtype = af; - hp->h_length = len; - (void)memcpy(host_addr, uaddr, (size_t)len); - h_addr_ptrs[0] = (char *)(void *)host_addr; - h_addr_ptrs[1] = NULL; - if (af == AF_INET && (res->options & RES_USE_INET6)) { - map_v4v6_address((char *)(void *)host_addr, - (char *)(void *)host_addr); + + bf = (void *)(hp->h_addr_list + 2); + blen = (size_t)(bf - info->buf); + if (blen + info->hp->h_length > info->buflen) + goto nospc; + hp->h_addr_list[0] = bf; + hp->h_addr_list[1] = NULL; + (void)memcpy(bf, uaddr, (size_t)info->hp->h_length); + if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) { + if (blen + NS_IN6ADDRSZ > info->buflen) + goto nospc; + map_v4v6_address(bf, bf); hp->h_addrtype = AF_INET6; - hp->h_length = IN6ADDRSZ; + hp->h_length = NS_IN6ADDRSZ; } __res_put_state(res); - *((struct hostent **)rv) = hp; - h_errno = NETDB_SUCCESS; + *info->he = NETDB_SUCCESS; return NS_SUCCESS; +nospc: + *info->he = NETDB_INTERNAL; + return NS_UNAVAIL; } #ifdef YP /*ARGSUSED*/ -struct hostent * -_yphostent(char *line, int af) +static struct hostent * +_yp_hostent(char *line, int af, struct getnamaddr *info) { - static struct in_addr host_addrs[MAXADDRS]; - static struct in6_addr host6_addrs[MAXADDRS]; + struct in6_addr host_addrs[MAXADDRS]; + char *aliases[MAXALIASES]; char *p = line; - char *cp, **q; - char **hap; + char *cp, **q, *ptr; + size_t len, anum, i; int addrok; int more; size_t naddrs; + struct hostent *hp = info->hp; _DIAGASSERT(line != NULL); - host.h_name = NULL; - host.h_addr_list = h_addr_ptrs; - host.h_addrtype = af; + hp->h_name = NULL; + hp->h_addrtype = af; switch (af) { case AF_INET: - host.h_length = INADDRSZ; + hp->h_length = NS_INADDRSZ; break; case AF_INET6: - host.h_length = IN6ADDRSZ; + hp->h_length = NS_IN6ADDRSZ; break; default: return NULL; } - hap = h_addr_ptrs; - q = host.h_aliases = host_aliases; naddrs = 0; + q = aliases; nextline: /* check for host_addrs overflow */ - if (naddrs >= sizeof(host_addrs) / sizeof(host_addrs[0])) - goto done; - if (naddrs >= sizeof(host6_addrs) / sizeof(host6_addrs[0])) + if (naddrs >= __arraycount(host_addrs)) goto done; more = 0; @@ -1277,15 +1347,7 @@ nextline: *cp++ = '\0'; /* p has should have an address */ - addrok = 0; - switch (af) { - case AF_INET: - addrok = inet_aton(p, &host_addrs[naddrs]); - break; - case AF_INET6: - addrok = inet_pton(af, p, &host6_addrs[naddrs]); - break; - } + addrok = inet_pton(af, p, &host_addrs[naddrs]); if (addrok != 1) { /* skip to the next line */ while (cp && *cp) { @@ -1295,19 +1357,9 @@ nextline: } cp++; } - goto done; } - switch (af) { - case AF_INET: - *hap++ = (char *)(void *)&host_addrs[naddrs++]; - break; - case AF_INET6: - *hap++ = (char *)(void *)&host6_addrs[naddrs++]; - break; - } - while (*cp == ' ' || *cp == '\t') cp++; p = cp; @@ -1317,11 +1369,11 @@ nextline: more = 1; *cp++ = '\0'; } - if (!host.h_name) - host.h_name = p; - else if (strcmp(host.h_name, p)==0) + if (!hp->h_name) + hp->h_name = p; + else if (strcmp(hp->h_name, p) == 0) ; - else if (q < &host_aliases[MAXALIASES - 1]) + else if (q < &aliases[MAXALIASES - 1]) *q++ = p; p = cp; if (more) @@ -1336,7 +1388,7 @@ nextline: cp++; goto nextline; } - if (q < &host_aliases[MAXALIASES - 1]) + if (q < &aliases[MAXALIASES - 1]) *q++ = cp; cp = strpbrk(cp, " \t"); if (cp != NULL) @@ -1344,11 +1396,32 @@ nextline: } done: - if (host.h_name == NULL) + if (hp->h_name == NULL) return NULL; - *q = NULL; - *hap = NULL; - return &host; + + ptr = info->buf; + len = info->buflen; + + anum = (size_t)(q - aliases); + ARRAY(hp->h_addr_list, naddrs, ptr, len); + ARRAY(hp->h_aliases, anum, ptr, len); + + for (i = 0; i < naddrs; i++) + COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length, + ptr, len); + hp->h_addr_list[naddrs] = NULL; + + SCOPY(hp->h_name, hp->h_name, ptr, len); + + for (i = 0; i < anum; i++) + SCOPY(hp->h_aliases[i], aliases[i], ptr, len); + hp->h_aliases[anum] = NULL; + + return hp; +nospc: + *info->he = NETDB_INTERNAL; + errno = ENOSPC; + return NULL; } /*ARGSUSED*/ @@ -1356,12 +1429,13 @@ int _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap) { struct hostent *hp = NULL; - static char *__ypcurrent; - int __ypcurrentlen, r; + char *ypcurrent; + int ypcurrentlen, r; char name[INET6_ADDRSTRLEN]; /* XXX enough? */ const unsigned char *uaddr; int af; const char *map; + struct getnamaddr *info = rv; _DIAGASSERT(rv != NULL); @@ -1379,9 +1453,6 @@ _yp_gethtbyaddr(void *rv, void *cb_data, */ if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL) return NS_UNAVAIL; - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; switch (af) { case AF_INET: map = "hosts.byaddr"; @@ -1390,15 +1461,18 @@ _yp_gethtbyaddr(void *rv, void *cb_data, map = "ipnodes.byaddr"; break; } + ypcurrent = NULL; r = yp_match(__ypdomain, map, name, - (int)strlen(name), &__ypcurrent, &__ypcurrentlen); + (int)strlen(name), &ypcurrent, &ypcurrentlen); if (r == 0) - hp = _yphostent(__ypcurrent, af); + hp = _yp_hostent(ypcurrent, af, info); + else + hp = NULL; + free(ypcurrent); if (hp == NULL) { - h_errno = HOST_NOT_FOUND; + *info->he = HOST_NOT_FOUND; return NS_NOTFOUND; } - *((struct hostent **)rv) = hp; return NS_SUCCESS; } @@ -1406,26 +1480,24 @@ _yp_gethtbyaddr(void *rv, void *cb_data, int _yp_gethtbyname(void *rv, void *cb_data, va_list ap) { - struct hostent *hp = NULL; - static char *__ypcurrent; - int __ypcurrentlen, r; + struct hostent *hp; + char *ypcurrent; + int ypcurrentlen, r; const char *name; int af; const char *map; + struct getnamaddr *info = rv; _DIAGASSERT(rv != NULL); name = va_arg(ap, char *); - /* NOSTRICT skip len */(void)va_arg(ap, int); + /* NOSTRICT skip string len */(void)va_arg(ap, int); af = va_arg(ap, int); if (!__ypdomain) { if (_yp_check(&__ypdomain) == 0) return NS_UNAVAIL; } - if (__ypcurrent) - free(__ypcurrent); - __ypcurrent = NULL; switch (af) { case AF_INET: map = "hosts.byname"; @@ -1434,15 +1506,56 @@ _yp_gethtbyname(void *rv, void *cb_data, map = "ipnodes.byname"; break; } + ypcurrent = NULL; r = yp_match(__ypdomain, map, name, - (int)strlen(name), &__ypcurrent, &__ypcurrentlen); + (int)strlen(name), &ypcurrent, &ypcurrentlen); if (r == 0) - hp = _yphostent(__ypcurrent, af); + hp = _yp_hostent(ypcurrent, af, info); + else + hp = NULL; + free(ypcurrent); if (hp == NULL) { - h_errno = HOST_NOT_FOUND; + *info->he = HOST_NOT_FOUND; return NS_NOTFOUND; } - *((struct hostent **)rv) = hp; return NS_SUCCESS; } #endif + +/* + * Non-reentrant versions. + */ +FILE *_h_file; +static struct hostent h_ent; +static char h_buf[16384]; + +struct hostent * +gethostbyaddr(const char *addr, socklen_t len, int af) { + return gethostbyaddr_r(addr, len, af, &h_ent, h_buf, sizeof(h_buf), + &h_errno); +} + +struct hostent * +gethostbyname(const char *name) { + return gethostbyname_r(name, &h_ent, h_buf, sizeof(h_buf), &h_errno); +} + +struct hostent * +gethostbyname2(const char *name, int af) { + return gethostbyname2_r(name, af, &h_ent, h_buf, sizeof(h_buf), + &h_errno); +} + +struct hostent * +gethostent(void) +{ + if (_h_file == NULL) { + sethostent_r(&_h_file); + if (_h_file == NULL) { + h_errno = NETDB_INTERNAL; + return NULL; + } + } + memset(&h_ent, 0, sizeof(h_ent)); + return gethostent_r(_h_file, &h_ent, h_buf, sizeof(h_buf), &h_errno); +} Index: src/lib/libc/net/getnameinfo.c diff -u src/lib/libc/net/getnameinfo.c:1.53 src/lib/libc/net/getnameinfo.c:1.54 --- src/lib/libc/net/getnameinfo.c:1.53 Wed Sep 26 19:13:00 2012 +++ src/lib/libc/net/getnameinfo.c Fri Aug 16 11:27:12 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: getnameinfo.c,v 1.53 2012/09/26 23:13:00 christos Exp $ */ +/* $NetBSD: getnameinfo.c,v 1.54 2013/08/16 15:27:12 christos Exp $ */ /* $KAME: getnameinfo.c,v 1.45 2000/09/25 22:43:56 itojun Exp $ */ /* @@ -47,7 +47,7 @@ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: getnameinfo.c,v 1.53 2012/09/26 23:13:00 christos Exp $"); +__RCSID("$NetBSD: getnameinfo.c,v 1.54 2013/08/16 15:27:12 christos Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" @@ -70,6 +70,7 @@ __RCSID("$NetBSD: getnameinfo.c,v 1.53 2 #include <string.h> #include "servent.h" +#include "hostent.h" #ifdef __weak_alias __weak_alias(getnameinfo,_getnameinfo) @@ -375,7 +376,11 @@ getnameinfo_inet(const struct sockaddr * break; } } else { - hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); + struct hostent hent; + char hbuf[4096]; + int he; + hp = gethostbyaddr_r(addr, afd->a_addrlen, afd->a_af, &hent, + hbuf, sizeof(hbuf), &he); if (hp) { #if 0 Index: src/lib/libc/net/sethostent.c diff -u src/lib/libc/net/sethostent.c:1.17 src/lib/libc/net/sethostent.c:1.18 --- src/lib/libc/net/sethostent.c:1.17 Tue Mar 20 13:44:18 2012 +++ src/lib/libc/net/sethostent.c Fri Aug 16 11:27:12 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: sethostent.c,v 1.17 2012/03/20 17:44:18 matt Exp $ */ +/* $NetBSD: sethostent.c,v 1.18 2013/08/16 15:27:12 christos Exp $ */ /* * Copyright (c) 1985, 1993 @@ -35,7 +35,7 @@ static char sccsid[] = "@(#)sethostent.c 8.1 (Berkeley) 6/4/93"; static char rcsid[] = "Id: sethostent.c,v 8.5 1996/09/28 06:51:07 vixie Exp "; #else -__RCSID("$NetBSD: sethostent.c,v 1.17 2012/03/20 17:44:18 matt Exp $"); +__RCSID("$NetBSD: sethostent.c,v 1.18 2013/08/16 15:27:12 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -46,16 +46,16 @@ __RCSID("$NetBSD: sethostent.c,v 1.17 20 #include <netdb.h> #include <resolv.h> +#include "hostent.h" + #ifdef __weak_alias __weak_alias(sethostent,_sethostent) __weak_alias(endhostent,_endhostent) #endif -void _endhtent(void); #ifndef _REENTRANT void res_close(void); #endif -void _sethtent(int); void /*ARGSUSED*/ @@ -67,7 +67,7 @@ sethostent(int stayopen) if (stayopen) _res.options |= RES_STAYOPEN | RES_USEVC; #endif - _sethtent(stayopen); + sethostent_r(&_h_file); } void @@ -77,5 +77,5 @@ endhostent(void) _res.options &= ~(RES_STAYOPEN | RES_USEVC); res_close(); #endif - _endhtent(); + endhostent_r(&_h_file); } Added files: Index: src/lib/libc/net/hostent.h diff -u /dev/null src/lib/libc/net/hostent.h:1.1 --- /dev/null Fri Aug 16 11:27:12 2013 +++ src/lib/libc/net/hostent.h Fri Aug 16 11:27:12 2013 @@ -0,0 +1,77 @@ +/* $NetBSD: hostent.h,v 1.1 2013/08/16 15:27:12 christos Exp $ */ + +/*- + * Copyright (c) 2013 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <netdb.h> +#include <stdarg.h> + +/* + * These are not being advertised because the interfaces are non-standard. + * There are versions by linux, aix, qnx, sun, etc. Our versions are used + * internally to provide thread safety; they mostly resemble qnx. + */ +void sethostent_r(FILE **); +struct hostent *gethostent_r(FILE *, struct hostent *, char *, size_t, int *); +void endhostent_r(FILE **); + +struct hostent *gethostbyname_r(const char *, struct hostent *, char *, size_t, + int *); +struct hostent *gethostbyname2_r(const char *, int, struct hostent *, char *, + size_t, int *); +struct hostent *gethostbyaddr_r(const void *, socklen_t, int, struct hostent *, + char *, size_t, int *); + +extern FILE *_h_file; + +/* + * The following are internal API's and are used only for testing. + */ +struct getnamaddr { + struct hostent *hp; + char *buf; + size_t buflen; + int *he; +}; + +/* /etc/hosts lookup */ +void _hf_sethostsfile(const char *); +int _hf_gethtbyaddr(void *, void *, va_list); +int _hf_gethtbyname(void *, void *, va_list); + +/* DNS lookup */ +int _dns_gethtbyaddr(void *, void *, va_list); +int _dns_gethtbyname(void *, void *, va_list); + +#ifdef YP +/* NIS lookup */ +int _yp_gethtbyaddr(void *, void *, va_list); +int _yp_gethtbyname(void *, void *, va_list); +#endif