diff options
author | Hajimu UMEMOTO <ume@FreeBSD.org> | 2005-04-28 18:03:43 +0000 |
---|---|---|
committer | Hajimu UMEMOTO <ume@FreeBSD.org> | 2005-04-28 18:03:43 +0000 |
commit | aa2f4ec72aa5a0edf89218a157cc36087316a2c5 (patch) | |
tree | bf4853f6b32bd035c380dd4ac79b8598d2682385 /lib | |
parent | 7b671d902bb803d5624f344f400b89833ecedf28 (diff) | |
download | src-aa2f4ec72aa5a0edf89218a157cc36087316a2c5.tar.gz src-aa2f4ec72aa5a0edf89218a157cc36087316a2c5.zip |
make gethostby*() thread-safe.
Notes
Notes:
svn path=/head/; revision=145633
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/net/gethostbydns.c | 184 | ||||
-rw-r--r-- | lib/libc/net/gethostbyht.c | 150 | ||||
-rw-r--r-- | lib/libc/net/gethostbyname.3 | 12 | ||||
-rw-r--r-- | lib/libc/net/gethostbynis.c | 142 | ||||
-rw-r--r-- | lib/libc/net/gethostnamadr.c | 232 | ||||
-rw-r--r-- | lib/libc/net/netdb_private.h | 43 |
6 files changed, 478 insertions, 285 deletions
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c index cc67011222d6..63bda784e422 100644 --- a/lib/libc/net/gethostbydns.c +++ b/lib/libc/net/gethostbydns.c @@ -84,19 +84,9 @@ __FBSDID("$FreeBSD$"); #define SPRINTF(x) ((size_t)sprintf x) -#define MAXALIASES 35 -#define MAXADDRS 35 - static const char AskedForGot[] = "gethostby*.gethostanswer: asked for \"%s\", got \"%s\""; -static char *h_addr_ptrs[MAXADDRS + 1]; - -static struct hostent host; -static char *host_aliases[MAXALIASES]; -static char hostbuf[8*1024]; -static u_char host_addr[16]; /* IPv4 or IPv6 */ - #ifdef RESOLVSORT static void addrsort(char **, int); #endif @@ -141,7 +131,7 @@ dprintf(msg, num) cp += x; \ if (cp > eom) { \ h_errno = NO_RECOVERY; \ - return (NULL); \ + return -1; \ } \ } while (0) @@ -149,16 +139,13 @@ dprintf(msg, num) do { \ if ((ptr) + (count) > eom) { \ h_errno = NO_RECOVERY; \ - return (NULL); \ + return -1; \ } \ } while (0) -static struct hostent * -gethostanswer(answer, anslen, qname, qtype) - const querybuf *answer; - int anslen; - const char *qname; - int qtype; +static int +gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype, + struct hostent *he, struct hostent_data *hed) { const HEADER *hp; const u_char *cp; @@ -173,7 +160,7 @@ gethostanswer(answer, anslen, qname, qtype) int (*name_ok)(const char *); tname = qname; - host.h_name = NULL; + he->h_name = NULL; eom = answer->buf + anslen; switch (qtype) { case T_A: @@ -185,7 +172,7 @@ gethostanswer(answer, anslen, qname, qtype) break; default: h_errno = NO_RECOVERY; - return (NULL); /* XXX should be abort(); */ + return -1; /* XXX should be abort(); */ } /* * find first satisfactory answer @@ -193,18 +180,18 @@ gethostanswer(answer, anslen, qname, qtype) hp = &answer->hdr; ancount = ntohs(hp->ancount); qdcount = ntohs(hp->qdcount); - bp = hostbuf; - ep = hostbuf + sizeof hostbuf; + bp = hed->hostbuf; + ep = hed->hostbuf + sizeof hed->hostbuf; cp = answer->buf; BOUNDED_INCR(HFIXEDSZ); if (qdcount != 1) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } n = dn_expand(answer->buf, eom, cp, bp, ep - bp); if ((n < 0) || !(*name_ok)(bp)) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } BOUNDED_INCR(n + QFIXEDSZ); if (qtype == T_A || qtype == T_AAAA) { @@ -215,19 +202,19 @@ gethostanswer(answer, anslen, qname, qtype) n = strlen(bp) + 1; /* for the \0 */ if (n >= MAXHOSTNAMELEN) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } - host.h_name = bp; + he->h_name = bp; bp += n; /* The qname can be abbreviated, but h_name is now absolute. */ - qname = host.h_name; + qname = he->h_name; } - ap = host_aliases; + ap = hed->host_aliases; *ap = NULL; - host.h_aliases = host_aliases; - hap = h_addr_ptrs; + he->h_aliases = hed->host_aliases; + hap = hed->h_addr_ptrs; *hap = NULL; - host.h_addr_list = h_addr_ptrs; + he->h_addr_list = hed->h_addr_ptrs; haveanswer = 0; had_error = 0; _dns_ttl_ = -1; @@ -256,7 +243,7 @@ gethostanswer(answer, anslen, qname, qtype) continue; /* XXX - had_error++ ? */ } if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) { - if (ap >= &host_aliases[MAXALIASES-1]) + if (ap >= &hed->host_aliases[_MAXALIASES-1]) continue; n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); if ((n < 0) || !(*name_ok)(tbuf)) { @@ -266,7 +253,7 @@ gethostanswer(answer, anslen, qname, qtype) cp += n; if (cp != erdata) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } /* Store alias. */ *ap++ = bp; @@ -283,7 +270,7 @@ gethostanswer(answer, anslen, qname, qtype) continue; } strcpy(bp, tbuf); - host.h_name = bp; + he->h_name = bp; bp += n; continue; } @@ -296,7 +283,7 @@ gethostanswer(answer, anslen, qname, qtype) cp += n; if (cp != erdata) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } /* Get canonical name. */ n = strlen(tbuf) + 1; /* for the \0 */ @@ -335,11 +322,11 @@ gethostanswer(answer, anslen, qname, qtype) cp += n; if (cp != erdata) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } if (!haveanswer) - host.h_name = bp; - else if (ap < &host_aliases[MAXALIASES-1]) + he->h_name = bp; + else if (ap < &hed->host_aliases[_MAXALIASES-1]) *ap++ = bp; else n = -1; @@ -353,7 +340,7 @@ gethostanswer(answer, anslen, qname, qtype) } break; #else - host.h_name = bp; + he->h_name = bp; if (_res.options & RES_USE_INET6) { n = strlen(bp) + 1; /* for the \0 */ if (n >= MAXHOSTNAMELEN) { @@ -361,27 +348,27 @@ gethostanswer(answer, anslen, qname, qtype) break; } bp += n; - _map_v4v6_hostent(&host, &bp, &ep); + _map_v4v6_hostent(he, &bp, &ep); } h_errno = NETDB_SUCCESS; - return (&host); + return 0; #endif case T_A: case T_AAAA: - if (strcasecmp(host.h_name, bp) != 0) { + if (strcasecmp(he->h_name, bp) != 0) { syslog(LOG_NOTICE|LOG_AUTH, - AskedForGot, host.h_name, bp); + AskedForGot, he->h_name, bp); cp += n; continue; /* XXX - had_error++ ? */ } - if (n != host.h_length) { + if (n != he->h_length) { cp += n; continue; } if (!haveanswer) { int nn; - host.h_name = bp; + he->h_name = bp; nn = strlen(bp) + 1; /* for the \0 */ bp += nn; } @@ -393,10 +380,10 @@ gethostanswer(answer, anslen, qname, qtype) had_error++; continue; } - if (hap >= &h_addr_ptrs[MAXADDRS-1]) { + if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) { if (!toobig++) dprintf("Too many addresses (%d)\n", - MAXADDRS); + _MAXADDRS); cp += n; continue; } @@ -405,13 +392,13 @@ gethostanswer(answer, anslen, qname, qtype) cp += n; if (cp != erdata) { h_errno = NO_RECOVERY; - return (NULL); + return -1; } break; default: dprintf("Impossible condition (type=%d)\n", type); h_errno = NO_RECOVERY; - return (NULL); + return -1; /* BIND has abort() here, too risky on bad data */ } if (!had_error) @@ -427,46 +414,52 @@ gethostanswer(answer, anslen, qname, qtype) * address in that case, not some random one */ if (_res.nsort && haveanswer > 1 && qtype == T_A) - addrsort(h_addr_ptrs, haveanswer); + addrsort(hed->h_addr_ptrs, haveanswer); # endif /*RESOLVSORT*/ - if (!host.h_name) { + if (!he->h_name) { n = strlen(qname) + 1; /* for the \0 */ if (n > ep - bp || n >= MAXHOSTNAMELEN) goto no_recovery; strcpy(bp, qname); - host.h_name = bp; + he->h_name = bp; bp += n; } if (_res.options & RES_USE_INET6) - _map_v4v6_hostent(&host, &bp, &ep); + _map_v4v6_hostent(he, &bp, &ep); h_errno = NETDB_SUCCESS; - return (&host); + return 0; } no_recovery: h_errno = NO_RECOVERY; - return (NULL); + return -1; } +/* XXX: for async DNS resolver in ypserv */ struct hostent * -__dns_getanswer(answer, anslen, qname, qtype) - const char *answer; - int anslen; - const char *qname; - int qtype; +__dns_getanswer(const char *answer, int anslen, const char *qname, int qtype) { - switch(qtype) { + struct hostdata *hd; + int error; + + if ((hd = __hostdata_init()) == NULL) { + h_errno = NETDB_INTERNAL; + return NULL; + } + switch (qtype) { case T_AAAA: - host.h_addrtype = AF_INET6; - host.h_length = IN6ADDRSZ; + hd->host.h_addrtype = AF_INET6; + hd->host.h_length = IN6ADDRSZ; break; case T_A: default: - host.h_addrtype = AF_INET; - host.h_length = INADDRSZ; + hd->host.h_addrtype = AF_INET; + hd->host.h_length = INADDRSZ; break; } - return(gethostanswer((const querybuf *)answer, anslen, qname, qtype)); + error = gethostanswer((const querybuf *)answer, anslen, qname, qtype, + &hd->host, &hd->data); + return (error == 0) ? &hd->host : NULL; } int @@ -474,12 +467,15 @@ _dns_gethostbyname(void *rval, void *cb_data, va_list ap) { const char *name; int af; + struct hostent *he; + struct hostent_data *hed; querybuf *buf; - int n, size, type; + int n, size, type, error; name = va_arg(ap, const char *); af = va_arg(ap, int); - *(struct hostent **)rval = NULL; + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); switch (af) { case AF_INET: @@ -496,8 +492,8 @@ _dns_gethostbyname(void *rval, void *cb_data, va_list ap) return NS_UNAVAIL; } - host.h_addrtype = af; - host.h_length = size; + he->h_addrtype = af; + he->h_length = size; if ((buf = malloc(sizeof(*buf))) == NULL) { h_errno = NETDB_INTERNAL; @@ -513,9 +509,9 @@ _dns_gethostbyname(void *rval, void *cb_data, va_list ap) dprintf("static buffer is too small (%d)\n", n); return (0); } - *(struct hostent **)rval = gethostanswer(buf, n, name, type); + error = gethostanswer(buf, n, name, type, he, hed); free(buf); - return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND; + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; } int @@ -523,15 +519,17 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) { const char *addr; /* XXX should have been def'd as u_char! */ int len, af; + struct hostent *he; + struct hostent_data *hed; const u_char *uaddr; static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff }; static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 }; - int n, size; + int n, size, error; querybuf *buf; - struct hostent *hp; char qbuf[MAXDNAME+1], *qp; #ifdef SUNSECURITY - struct hostent *rhp; + struct hostdata rhd; + struct hostent *rhe; char **haddr; u_long old_options; char hname2[MAXDNAME+1]; @@ -541,9 +539,9 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) uaddr = (const u_char *)addr; len = va_arg(ap, int); af = va_arg(ap, int); - - *(struct hostent **)rval = NULL; - + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); + if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; return NS_UNAVAIL; @@ -609,7 +607,7 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) dprintf("static buffer is too small (%d)\n", n); return NS_UNAVAIL; } - if (!(hp = gethostanswer(buf, n, qbuf, T_PTR))) { + if ((error = gethostanswer(buf, n, qbuf, T_PTR, he, hed)) != 0) { free(buf); return NS_NOTFOUND; /* h_errno was set by gethostanswer() */ } @@ -620,12 +618,13 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) * turn off search as the name should be absolute, * 'localhost' should be matched by defnames */ - strncpy(hname2, hp->h_name, MAXDNAME); + strncpy(hname2, he->h_name, MAXDNAME); hname2[MAXDNAME] = '\0'; old_options = _res.options; _res.options &= ~RES_DNSRCH; _res.options |= RES_DEFNAMES; - if (!(rhp = gethostbyname(hname2))) { + memset(&rhd, 0, sizeof rhd); + if (!(rhe = gethostbyname_r(hname2, &rhd.host, &rhd.data))) { syslog(LOG_NOTICE|LOG_AUTH, "gethostbyaddr: No A record for %s (verifying [%s])", hname2, inet_ntoa(*((struct in_addr *)addr))); @@ -634,7 +633,7 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) return NS_NOTFOUND; } _res.options = old_options; - for (haddr = rhp->h_addr_list; *haddr; haddr++) + for (haddr = rhe->h_addr_list; *haddr; haddr++) if (!memcmp(*haddr, addr, INADDRSZ)) break; if (!*haddr) { @@ -646,19 +645,18 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap) } } #endif /*SUNSECURITY*/ - hp->h_addrtype = af; - hp->h_length = len; - bcopy(addr, host_addr, len); - h_addr_ptrs[0] = (char *)host_addr; - h_addr_ptrs[1] = NULL; + he->h_addrtype = af; + he->h_length = len; + bcopy(addr, hed->host_addr, len); + hed->h_addr_ptrs[0] = (char *)hed->host_addr; + hed->h_addr_ptrs[1] = NULL; if (af == AF_INET && (_res.options & RES_USE_INET6)) { - _map_v4v6_address((char*)host_addr, (char*)host_addr); - hp->h_addrtype = AF_INET6; - hp->h_length = IN6ADDRSZ; + _map_v4v6_address((char*)hed->host_addr, (char*)hed->host_addr); + he->h_addrtype = AF_INET6; + he->h_length = IN6ADDRSZ; } h_errno = NETDB_SUCCESS; - *(struct hostent **)rval = hp; - return (hp != NULL) ? NS_SUCCESS : NS_NOTFOUND; + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; } #ifdef RESOLVSORT @@ -669,7 +667,7 @@ addrsort(ap, num) { int i, j; char **p; - short aval[MAXADDRS]; + short aval[_MAXADDRS]; int needsort = 0; p = ap; diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c index 0318adbb010c..efa8269c4604 100644 --- a/lib/libc/net/gethostbyht.c +++ b/lib/libc/net/gethostbyht.c @@ -71,51 +71,41 @@ __FBSDID("$FreeBSD$"); #include <resolv.h> /* XXX */ #include "netdb_private.h" -#define MAXALIASES 35 - -static struct hostent host; -static char *host_aliases[MAXALIASES]; -static char hostbuf[BUFSIZ+1]; -static FILE *hostf = NULL; -static u_int32_t host_addr[4]; /* IPv4 or IPv6 */ -static char *h_addr_ptrs[2]; -static int stayopen = 0; - void -_sethosthtent(f) - int f; +_sethosthtent(int f, struct hostent_data *hed) { - if (!hostf) - hostf = fopen(_PATH_HOSTS, "r" ); + if (!hed->hostf) + hed->hostf = fopen(_PATH_HOSTS, "r"); else - rewind(hostf); - stayopen = f; + rewind(hed->hostf); + hed->stayopen = f; } void -_endhosthtent() +_endhosthtent(struct hostent_data *hed) { - if (hostf && !stayopen) { - (void) fclose(hostf); - hostf = NULL; + if (hed->hostf && !hed->stayopen) { + (void) fclose(hed->hostf); + hed->hostf = NULL; } } -struct hostent * -gethostent() +int +gethostent_r(struct hostent *he, struct hostent_data *hed) { - char *p; + char *p, *bp, *ep; char *cp, **q; int af, len; + char hostbuf[BUFSIZ + 1]; - if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) { + if (!hed->hostf && !(hed->hostf = fopen(_PATH_HOSTS, "r"))) { h_errno = NETDB_INTERNAL; - return (NULL); + return -1; } again: - if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) { + if (!(p = fgets(hostbuf, sizeof hostbuf, hed->hostf))) { h_errno = HOST_NOT_FOUND; - return (NULL); + return -1; } if (*p == '#') goto again; @@ -125,12 +115,13 @@ gethostent() if (!(cp = strpbrk(p, " \t"))) goto again; *cp++ = '\0'; - if (inet_pton(AF_INET6, p, host_addr) > 0) { + if (inet_pton(AF_INET6, p, hed->host_addr) > 0) { af = AF_INET6; len = IN6ADDRSZ; - } else if (inet_pton(AF_INET, p, host_addr) > 0) { + } else if (inet_pton(AF_INET, p, hed->host_addr) > 0) { if (_res.options & RES_USE_INET6) { - _map_v4v6_address((char*)host_addr, (char*)host_addr); + _map_v4v6_address((char *)hed->host_addr, + (char *)hed->host_addr); af = AF_INET6; len = IN6ADDRSZ; } else { @@ -140,30 +131,59 @@ gethostent() } else { goto again; } - h_addr_ptrs[0] = (char *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; - host.h_length = len; - host.h_addrtype = af; + hed->h_addr_ptrs[0] = (char *)hed->host_addr; + hed->h_addr_ptrs[1] = NULL; + he->h_addr_list = hed->h_addr_ptrs; + he->h_length = len; + he->h_addrtype = af; while (*cp == ' ' || *cp == '\t') cp++; - host.h_name = cp; - q = host.h_aliases = host_aliases; - if ((cp = strpbrk(cp, " \t")) != NULL) - *cp++ = '\0'; + bp = hed->hostbuf; + ep = hed->hostbuf + sizeof hed->hostbuf; + he->h_name = bp; + q = he->h_aliases = hed->host_aliases; + if ((p = strpbrk(cp, " \t")) != NULL) + *p++ = '\0'; + len = strlen(cp) + 1; + if (ep - bp < len) { + h_errno = NETDB_INTERNAL; + return -1; + } + strlcpy(bp, cp, ep - bp); + bp += len; + cp = p; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } - if (q < &host_aliases[MAXALIASES - 1]) - *q++ = cp; - if ((cp = strpbrk(cp, " \t")) != NULL) - *cp++ = '\0'; + if (q >= &hed->host_aliases[_MAXALIASES - 1]) + break; + if ((p = strpbrk(cp, " \t")) != NULL) + *p++ = '\0'; + len = strlen(cp) + 1; + if (ep - bp < len) + break; + strlcpy(bp, cp, ep - bp); + *q++ = bp; + bp += len; + cp = p; } *q = NULL; h_errno = NETDB_SUCCESS; - return (&host); + return 0; +} + +struct hostent * +gethostent(void) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return NULL; + if (gethostent_r(&hd->host, &hd->data) != 0) + return NULL; + return &hd->host; } int @@ -171,27 +191,30 @@ _ht_gethostbyname(void *rval, void *cb_data, va_list ap) { const char *name; int af; - struct hostent *p; + struct hostent *he; + struct hostent_data *hed; char **cp; + int error; name = va_arg(ap, const char *); af = va_arg(ap, int); - - sethostent(0); - while ((p = gethostent()) != NULL) { - if (p->h_addrtype != af) + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); + + sethostent_r(0, hed); + while ((error = gethostent_r(he, hed)) == 0) { + if (he->h_addrtype != af) continue; - if (strcasecmp(p->h_name, name) == 0) + if (strcasecmp(he->h_name, name) == 0) break; - for (cp = p->h_aliases; *cp != 0; cp++) + for (cp = he->h_aliases; *cp != 0; cp++) if (strcasecmp(*cp, name) == 0) goto found; } found: - endhostent(); - *(struct hostent **)rval = p; - - return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND; + endhostent_r(hed); + + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; } int @@ -199,18 +222,21 @@ _ht_gethostbyaddr(void *rval, void *cb_data, va_list ap) { const char *addr; int len, af; - struct hostent *p; + struct hostent *he; + struct hostent_data *hed; + int error; addr = va_arg(ap, const char *); len = va_arg(ap, int); af = va_arg(ap, int); + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); - sethostent(0); - while ((p = gethostent()) != NULL) - if (p->h_addrtype == af && !bcmp(p->h_addr, addr, len)) + sethostent_r(0, hed); + while ((error = gethostent_r(he, hed)) == 0) + if (he->h_addrtype == af && !bcmp(he->h_addr, addr, len)) break; - endhostent(); + endhostent_r(hed); - *(struct hostent **)rval = p; - return (p != NULL) ? NS_SUCCESS : NS_NOTFOUND; + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; } diff --git a/lib/libc/net/gethostbyname.3 b/lib/libc/net/gethostbyname.3 index 3d92af612ec0..6f9ee0dce1f1 100644 --- a/lib/libc/net/gethostbyname.3 +++ b/lib/libc/net/gethostbyname.3 @@ -366,14 +366,14 @@ function first appeared in .Tn BIND version 4.9.4. .Sh BUGS -These functions use static data storage; +These functions use a thread-specific data storage; if the data is needed for future use, it should be copied before any subsequent calls overwrite it. -Threaded applications should never use them, as they will also conflict -with the +.Pp +Though these functions are thread-safe, +still it is recommended to use the .Xr getaddrinfo 3 -and -.Xr getipnodebyname 3 -families of functions (which should be used instead). +family of functions, instead. +.Pp Only the Internet address format is currently understood. diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c index 0c5b3e8dcdcb..386b31259bf9 100644 --- a/lib/libc/net/gethostbynis.c +++ b/lib/libc/net/gethostbynis.c @@ -44,27 +44,18 @@ __FBSDID("$FreeBSD$"); #include <rpcsvc/yp_prot.h> #include <rpcsvc/ypclnt.h> #endif - -#define MAXALIASES 35 -#define MAXADDRS 35 +#include "netdb_private.h" #ifdef YP -static char *host_aliases[MAXALIASES]; -static uint32_t host_addr[4]; /* IPv4 or IPv6 */ -static char *host_addrs[2]; - -static struct hostent * -_gethostbynis(name, map, af) - const char *name; - char *map; - int af; +static int +_gethostbynis(const char *name, char *map, int af, struct hostent *he, + struct hostent_data *hed) { + char *p, *bp, *ep; char *cp, **q; char *result; int resultlen, size, addrok = 0; - static struct hostent h; - static char *domain = (char *)NULL; - static char ypbuf[YPMAXRECORD + 2]; + char ypbuf[YPMAXRECORD + 2]; switch(af) { case AF_INET: @@ -76,18 +67,19 @@ _gethostbynis(name, map, af) default: errno = EAFNOSUPPORT; h_errno = NETDB_INTERNAL; - return NULL; + return -1; } - if (domain == (char *)NULL) - if (yp_get_default_domain (&domain)) { + if (hed->yp_domain == (char *)NULL) + if (yp_get_default_domain (&hed->yp_domain)) { h_errno = NETDB_INTERNAL; - return ((struct hostent *)NULL); + return -1; } - if (yp_match(domain, map, name, strlen(name), &result, &resultlen)) { + if (yp_match(hed->yp_domain, map, name, strlen(name), &result, + &resultlen)) { h_errno = HOST_NOT_FOUND; - return ((struct hostent *)NULL); + return -1; } /* avoid potential memory leak */ @@ -101,46 +93,65 @@ _gethostbynis(name, map, af) cp = strpbrk(result, " \t"); *cp++ = '\0'; - h.h_addr_list = host_addrs; - h.h_addr = (char *)host_addr; + he->h_addr_list = hed->h_addr_ptrs; + he->h_addr = (char *)hed->host_addr; switch (af) { case AF_INET: - addrok = inet_aton(result, (struct in_addr *)host_addr); + addrok = inet_aton(result, (struct in_addr *)hed->host_addr); break; case AF_INET6: - addrok = inet_pton(af, result, host_addr); + addrok = inet_pton(af, result, hed->host_addr); break; } if (addrok != 1) { h_errno = HOST_NOT_FOUND; - return NULL; + return -1; } - h.h_length = size; - h.h_addrtype = af; + he->h_addr_list[1] = NULL; + he->h_length = size; + he->h_addrtype = af; while (*cp == ' ' || *cp == '\t') cp++; - h.h_name = cp; - q = h.h_aliases = host_aliases; - cp = strpbrk(cp, " \t"); - if (cp != NULL) - *cp++ = '\0'; + bp = hed->hostbuf; + ep = hed->hostbuf + sizeof hed->hostbuf; + he->h_name = bp; + q = he->h_aliases = hed->host_aliases; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + size = strlen(cp) + 1; + if (ep - bp < size) { + h_errno = NETDB_INTERNAL; + return -1; + } + strlcpy(bp, cp, ep - bp); + bp += size; + cp = p; while (cp && *cp) { if (*cp == ' ' || *cp == '\t') { cp++; continue; } - if (q < &host_aliases[MAXALIASES - 1]) - *q++ = cp; - cp = strpbrk(cp, " \t"); - if (cp != NULL) - *cp++ = '\0'; + if (q >= &hed->host_aliases[_MAXALIASES - 1]) + break; + p = strpbrk(cp, " \t"); + if (p != NULL) + *p++ = '\0'; + size = strlen(cp) + 1; + if (ep - bp < size) + break; + strlcpy(bp, cp, ep - bp); + *q++ = bp; + bp += size; + cp = p; } *q = NULL; - return (&h); + return 0; } -static struct hostent * -_gethostbynisname_p(const char *name, int af) +static int +_gethostbynisname_r(const char *name, int af, struct hostent *he, + struct hostent_data *hed) { char *map; @@ -152,11 +163,12 @@ _gethostbynisname_p(const char *name, int af) map = "ipnodes.byname"; break; } - return _gethostbynis(name, map, af); + return _gethostbynis(name, map, af, he, hed); } -static struct hostent * -_gethostbynisaddr_p(const char *addr, int len, int af) +static int +_gethostbynisaddr_r(const char *addr, int len, int af, struct hostent *he, + struct hostent_data *hed) { char *map; @@ -168,7 +180,8 @@ _gethostbynisaddr_p(const char *addr, int len, int af) map = "ipnodes.byaddr"; break; } - return _gethostbynis(inet_ntoa(*(struct in_addr *)addr), map, af); + return _gethostbynis(inet_ntoa(*(struct in_addr *)addr), map, af, he, + hed); } #endif /* YP */ @@ -177,7 +190,15 @@ struct hostent * _gethostbynisname(const char *name, int af) { #ifdef YP - return _gethostbynisname_p(name, af); + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) { + h_errno = NETDB_INTERNAL; + return NULL; + } + if (_gethostbynisname_r(name, af, &hd->host, &hd->data) != 0) + return NULL; + return &hd->host; #else return NULL; #endif @@ -187,25 +208,37 @@ struct hostent * _gethostbynisaddr(const char *addr, int len, int af) { #ifdef YP - return _gethostbynisaddr_p(addr, len, af); + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) { + h_errno = NETDB_INTERNAL; + return NULL; + } + if (_gethostbynisaddr_r(addr, len, af, &hd->host, &hd->data) != 0) + return NULL; + return &hd->host; #else return NULL; #endif } - int _nis_gethostbyname(void *rval, void *cb_data, va_list ap) { #ifdef YP const char *name; int af; + struct hostent *he; + struct hostent_data *hed; + int error; name = va_arg(ap, const char *); af = va_arg(ap, int); + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); - *(struct hostent **)rval = _gethostbynisname_p(name, af); - return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND; + error = _gethostbynisname_r(name, af, he, hed); + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; #else return NS_UNAVAIL; #endif @@ -218,13 +251,18 @@ _nis_gethostbyaddr(void *rval, void *cb_data, va_list ap) const char *addr; int len; int af; + struct hostent *he; + struct hostent_data *hed; + int error; addr = va_arg(ap, const char *); len = va_arg(ap, int); af = va_arg(ap, int); + he = va_arg(ap, struct hostent *); + hed = va_arg(ap, struct hostent_data *); - *(struct hostent **)rval =_gethostbynisaddr_p(addr, len, af); - return (*(struct hostent **)rval != NULL) ? NS_SUCCESS : NS_NOTFOUND; + error = _gethostbynisaddr_r(addr, len, af, he, hed); + return (error == 0) ? NS_SUCCESS : NS_NOTFOUND; #else return NS_UNAVAIL; #endif diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c index 66348eaa713b..6c94d9877acf 100644 --- a/lib/libc/net/gethostnamadr.c +++ b/lib/libc/net/gethostnamadr.c @@ -27,6 +27,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" +#include "reentrant.h" #include <sys/param.h> #include <sys/socket.h> #include <netinet/in.h> @@ -35,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <ctype.h> #include <errno.h> +#include <stdlib.h> #include <string.h> #include <stdarg.h> #include <nsswitch.h> @@ -51,7 +53,8 @@ extern int _dns_gethostbyaddr(void *, void *, va_list); extern int _nis_gethostbyaddr(void *, void *, va_list); extern const char *_res_hostalias(const char *, char *, size_t); -static struct hostent *gethostbyname_internal(const char *, int); +static int gethostbyname_internal(const char *, int, struct hostent *, + struct hostent_data *); /* Host lookup order if nsswitch.conf is broken or nonexistant */ static const ns_src default_src[] = { @@ -60,47 +63,87 @@ static const ns_src default_src[] = { { 0 } }; -struct hostent * -gethostbyname(const char *name) +static struct hostdata hostdata; +static thread_key_t hostdata_key; +static once_t hostdata_init_once = ONCE_INITIALIZER; +static int hostdata_thr_keycreated = 0; + +static void +hostdata_free(void *ptr) +{ + struct hostdata *hd = ptr; + + if (hd == NULL) + return; + hd->data.stayopen = 0; + _endhosthtent(&hd->data); + free(hd); +} + +static void +hostdata_keycreate(void) { - struct hostent *hp; + hostdata_thr_keycreated = + (thr_keycreate(&hostdata_key, hostdata_free) == 0); +} + +struct hostdata * +__hostdata_init(void) +{ + struct hostdata *hd; + + if (thr_main() != 0) + return &hostdata; + if (thr_once(&hostdata_init_once, hostdata_keycreate) != 0 || + !hostdata_thr_keycreated) + return NULL; + if ((hd = thr_getspecific(hostdata_key)) != NULL) + return hd; + if ((hd = calloc(1, sizeof(*hd))) == NULL) + return NULL; + if (thr_setspecific(hostdata_key, hd) == 0) + return hd; + free(hd); + return NULL; +} + +int +gethostbyname_r(const char *name, struct hostent *he, struct hostent_data *hed) +{ + int error; if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; - return NULL; + return -1; } if (_res.options & RES_USE_INET6) { - hp = gethostbyname_internal(name, AF_INET6); - if (hp) - return hp; + error = gethostbyname_internal(name, AF_INET6, he, hed); + if (error == 0) + return 0; } - return gethostbyname_internal(name, AF_INET); + return gethostbyname_internal(name, AF_INET, he, hed); } -struct hostent * -gethostbyname2(const char *name, int af) +int +gethostbyname2_r(const char *name, int af, struct hostent *he, + struct hostent_data *hed) { if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; - return NULL; + return -1; } - return gethostbyname_internal(name, af); + return gethostbyname_internal(name, af, he, hed); } -static struct hostent * -gethostbyname_internal(const char *name, int af) +static int +gethostbyname_internal(const char *name, int af, struct hostent *he, + struct hostent_data *hed) { const char *cp; char *bp, *ep; - struct hostent *hp = 0; int size, rval; char abuf[MAXDNAME]; - static struct hostent host; - static char *h_addr_ptrs[2]; - static char *host_aliases[1]; - static char hostbuf[MAXDNAME + IN6ADDRSZ + sizeof(uint32_t)]; - static uint32_t host_addr[4]; /* IPv4 or IPv6 */ static const ns_dtab dtab[] = { NS_FILES_CB(_ht_gethostbyname, NULL) { NSSRC_DNS, _dns_gethostbyname, NULL }, @@ -118,11 +161,11 @@ gethostbyname_internal(const char *name, int af) default: h_errno = NETDB_INTERNAL; errno = EAFNOSUPPORT; - return NULL; + return -1; } - host.h_addrtype = af; - host.h_length = size; + he->h_addrtype = af; + he->h_length = size; /* * if there aren't any dots, it could be a user-level alias. @@ -147,24 +190,24 @@ gethostbyname_internal(const char *name, int af) * Fake up a hostent as if we'd actually * done a lookup. */ - if (inet_pton(af, name, host_addr) <= 0) { + if (inet_pton(af, name, hed->host_addr) <= 0) { h_errno = HOST_NOT_FOUND; - return NULL; + return -1; } - 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 *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; + strncpy(hed->hostbuf, name, MAXDNAME); + hed->hostbuf[MAXDNAME] = '\0'; + bp = hed->hostbuf + MAXDNAME + 1; + ep = hed->hostbuf + sizeof hed->hostbuf; + he->h_name = hed->hostbuf; + he->h_aliases = hed->host_aliases; + hed->host_aliases[0] = NULL; + hed->h_addr_ptrs[0] = (char *)hed->host_addr; + hed->h_addr_ptrs[1] = NULL; + he->h_addr_list = hed->h_addr_ptrs; if (_res.options & RES_USE_INET6) - _map_v4v6_hostent(&host, &bp, &ep); + _map_v4v6_hostent(he, &bp, &ep); h_errno = NETDB_SUCCESS; - return &host; + return 0; } if (!isdigit((u_char)*cp) && *cp != '.') break; @@ -180,38 +223,35 @@ gethostbyname_internal(const char *name, int af) * Fake up a hostent as if we'd actually * done a lookup. */ - if (inet_pton(af, name, host_addr) <= 0) { + if (inet_pton(af, name, hed->host_addr) <= 0) { h_errno = HOST_NOT_FOUND; - return NULL; + return -1; } - strncpy(hostbuf, name, MAXDNAME); - hostbuf[MAXDNAME] = '\0'; - host.h_name = hostbuf; - host.h_aliases = host_aliases; - host_aliases[0] = NULL; - h_addr_ptrs[0] = (char *)host_addr; - h_addr_ptrs[1] = NULL; - host.h_addr_list = h_addr_ptrs; + strncpy(hed->hostbuf, name, MAXDNAME); + hed->hostbuf[MAXDNAME] = '\0'; + he->h_name = hed->hostbuf; + he->h_aliases = hed->host_aliases; + hed->host_aliases[0] = NULL; + hed->h_addr_ptrs[0] = (char *)hed->host_addr; + hed->h_addr_ptrs[1] = NULL; + he->h_addr_list = hed->h_addr_ptrs; h_errno = NETDB_SUCCESS; - return &host; + return 0; } if (!isxdigit((u_char)*cp) && *cp != ':' && *cp != '.') break; } - rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyname", - default_src, name, af); + rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyname", + default_src, name, af, he, hed); - if (rval != NS_SUCCESS) - return NULL; - else - return hp; + return (rval == NS_SUCCESS) ? 0 : -1; } -struct hostent * -gethostbyaddr(const char *addr, int len, int type) +int +gethostbyaddr_r(const char *addr, int len, int af, struct hostent *he, + struct hostent_data *hed) { - struct hostent *hp = 0; int rval; static const ns_dtab dtab[] = { @@ -219,28 +259,80 @@ gethostbyaddr(const char *addr, int len, int type) { NSSRC_DNS, _dns_gethostbyaddr, NULL }, NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */ { 0 } - }; + }; - rval = _nsdispatch((void *)&hp, dtab, NSDB_HOSTS, "gethostbyaddr", - default_src, addr, len, type); + rval = _nsdispatch(NULL, dtab, NSDB_HOSTS, "gethostbyaddr", + default_src, addr, len, af, he, hed); - if (rval != NS_SUCCESS) - return NULL; - else - return hp; + return (rval == NS_SUCCESS) ? 0 : -1; } void -sethostent(stayopen) - int stayopen; +sethostent_r(int stayopen, struct hostent_data *hed) { - _sethosthtent(stayopen); + _sethosthtent(stayopen, hed); _sethostdnsent(stayopen); } void -endhostent() +endhostent_r(struct hostent_data *hed) { - _endhosthtent(); + _endhosthtent(hed); _endhostdnsent(); } + +struct hostent * +gethostbyname(const char *name) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return NULL; + if (gethostbyname_r(name, &hd->host, &hd->data) != 0) + return NULL; + return &hd->host; +} + +struct hostent * +gethostbyname2(const char *name, int af) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return NULL; + if (gethostbyname2_r(name, af, &hd->host, &hd->data) != 0) + return NULL; + return &hd->host; +} + +struct hostent * +gethostbyaddr(const char *addr, int len, int af) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return NULL; + if (gethostbyaddr_r(addr, len, af, &hd->host, &hd->data) != 0) + return NULL; + return &hd->host; +} + +void +sethostent(int stayopen) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return; + sethostent_r(stayopen, &hd->data); +} + +void +endhostent(void) +{ + struct hostdata *hd; + + if ((hd = __hostdata_init()) == NULL) + return; + endhostent_r(&hd->data); +} diff --git a/lib/libc/net/netdb_private.h b/lib/libc/net/netdb_private.h index 141d5548813f..aa28ee75bf11 100644 --- a/lib/libc/net/netdb_private.h +++ b/lib/libc/net/netdb_private.h @@ -28,13 +28,32 @@ #ifndef _NETDB_PRIVATE_H_ #define _NETDB_PRIVATE_H_ +#include <sys/_types.h> #include <stdio.h> /* XXX: for FILE */ +#ifndef _UINT32_T_DECLARED +typedef __uint32_t uint32_t; +#define _UINT32_T_DECLARED +#endif + #define _MAXALIASES 35 #define _MAXLINELEN 1024 #define _MAXADDRS 35 +#define _HOSTBUFSIZE (8 * 1024) #define _NETBUFSIZE 1025 +struct hostent_data { + uint32_t host_addr[4]; /* IPv4 or IPv6 */ + char *h_addr_ptrs[_MAXADDRS + 1]; + char *host_aliases[_MAXALIASES]; + char hostbuf[_HOSTBUFSIZE]; + FILE *hostf; + int stayopen; +#ifdef YP + char *yp_domain; +#endif +}; + struct netent_data { char *net_aliases[_MAXALIASES]; char netbuf[_NETBUFSIZE]; @@ -68,6 +87,11 @@ struct servent_data { #endif }; +struct hostdata { + struct hostent host; + struct hostent_data data; +}; + struct netdata { struct netent net; struct netent_data data; @@ -83,9 +107,14 @@ struct servdata { struct servent_data data; }; +#define endhostent_r __endhostent_r #define endnetent_r __endnetent_r #define endprotoent_r __endprotoent_r #define endservent_r __endservent_r +#define gethostbyaddr_r __gethostbyaddr_r +#define gethostbyname_r __gethostbyname_r +#define gethostbyname2_r __gethostbyname2_r +#define gethostent_r __gethostent_r #define getnetbyaddr_r __getnetbyaddr_r #define getnetbyname_r __getnetbyname_r #define getnetent_r __getnetent_r @@ -95,15 +124,17 @@ struct servdata { #define getservbyname_r __getservbyname_r #define getservbyport_r __getservbyport_r #define getservent_r __getservent_r +#define sethostent_r __sethostent_r #define setnetent_r __setnetent_r #define setprotoent_r __setprotoent_r #define setservent_r __setservent_r +struct hostdata *__hostdata_init(void); struct netdata *__netdata_init(void); struct protodata *__protodata_init(void); struct servdata *__servdata_init(void); void _endhostdnsent(void); -void _endhosthtent(void); +void _endhosthtent(struct hostent_data *); void _endnetdnsent(void); void _endnethtent(struct netent_data *); struct hostent *_gethostbynisaddr(const char *, int, int); @@ -111,12 +142,19 @@ struct hostent *_gethostbynisname(const char *, int); void _map_v4v6_address(const char *, char *); void _map_v4v6_hostent(struct hostent *, char **, char **); void _sethostdnsent(int); -void _sethosthtent(int); +void _sethosthtent(int, struct hostent_data *); void _setnetdnsent(int); void _setnethtent(int, struct netent_data *); +void endhostent_r(struct hostent_data *); void endnetent_r(struct netent_data *); void endprotoent_r(struct protoent_data *); void endservent_r(struct servent_data *); +int gethostbyaddr_r(const char *, int, int, struct hostent *, + struct hostent_data *); +int gethostbyname_r(const char *, struct hostent *, struct hostent_data *); +int gethostbyname2_r(const char *, int, struct hostent *, + struct hostent_data *); +int gethostent_r(struct hostent *, struct hostent_data *); int getnetbyaddr_r(unsigned long addr, int af, struct netent *, struct netent_data *); int getnetbyname_r(const char *, struct netent *, struct netent_data *); @@ -129,6 +167,7 @@ int getservbyname_r(const char *, const char *, struct servent *, int getservbyport_r(int, const char *, struct servent *, struct servent_data *); int getservent_r(struct servent *, struct servent_data *); +void sethostent_r(int, struct hostent_data *); void setnetent_r(int, struct netent_data *); void setprotoent_r(int, struct protoent_data *); void setservent_r(int, struct servent_data *); |