|  | /*	$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $	*/ | 
|  |  | 
|  | /* | 
|  | * Copyright (c) 1985, 1993 | 
|  | *	The Regents of the University of California.  All rights reserved. | 
|  | * | 
|  | * 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. | 
|  | * 3. Neither the name of the University nor the names of its contributors | 
|  | *    may be used to endorse or promote products derived from this software | 
|  | *    without specific prior written permission. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <sys/cdefs.h> | 
|  | #if defined(LIBC_SCCS) && !defined(lint) | 
|  | #if 0 | 
|  | 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.20 2014/03/17 13:24:23 christos Exp $"); | 
|  | #endif | 
|  | #endif /* LIBC_SCCS and not lint */ | 
|  |  | 
|  | #include "namespace.h" | 
|  | #include <sys/param.h> | 
|  | #include <netinet/in.h> | 
|  | #include <arpa/nameser.h> | 
|  | #include <arpa/inet.h> | 
|  | #include <assert.h> | 
|  | #include <string.h> | 
|  | #include <nsswitch.h> | 
|  | #include <netdb.h> | 
|  | #include <resolv.h> | 
|  | #include <errno.h> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "hostent.h" | 
|  | #include "resolv_private.h" | 
|  |  | 
|  | #define ALIGNBYTES (sizeof(uintptr_t) - 1) | 
|  | #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) | 
|  |  | 
|  | #ifndef _REENTRANT | 
|  | void	res_close(void); | 
|  | #endif | 
|  |  | 
|  | static struct hostent *_hf_gethtbyname2(const char *, int, struct getnamaddr *); | 
|  |  | 
|  | void | 
|  | /*ARGSUSED*/ | 
|  | sethostent(int stayopen) | 
|  | { | 
|  | res_static rs = __res_get_static(); | 
|  | if (rs) sethostent_r(&rs->hostf); | 
|  | } | 
|  |  | 
|  | void | 
|  | endhostent(void) | 
|  | { | 
|  | res_static rs = __res_get_static(); | 
|  | if (rs) endhostent_r(&rs->hostf); | 
|  | } | 
|  |  | 
|  | void | 
|  | sethostent_r(FILE **hf) | 
|  | { | 
|  | if (!*hf) | 
|  | *hf = fopen(_PATH_HOSTS, "re"); | 
|  | else | 
|  | rewind(*hf); | 
|  | } | 
|  |  | 
|  | void | 
|  | endhostent_r(FILE **hf) | 
|  | { | 
|  | if (*hf) { | 
|  | (void)fclose(*hf); | 
|  | *hf = NULL; | 
|  | } | 
|  | } | 
|  |  | 
|  | /*ARGSUSED*/ | 
|  | int | 
|  | _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 string len */(void)va_arg(ap, int); | 
|  | af = va_arg(ap, int); | 
|  |  | 
|  | #if 0 | 
|  | { | 
|  | res_state res = __res_get_state(); | 
|  | if (res == NULL) | 
|  | return NS_NOTFOUND; | 
|  | if (res->options & RES_USE_INET6) | 
|  | 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 = _hf_gethtbyname2(name, af, info); | 
|  | #endif | 
|  | if (hp == NULL) { | 
|  | if (*info->he == NETDB_INTERNAL && errno == ENOSPC) { | 
|  | return NS_UNAVAIL; // glibc compatibility. | 
|  | } | 
|  | *info->he = HOST_NOT_FOUND; | 
|  | return NS_NOTFOUND; | 
|  | } | 
|  | return NS_SUCCESS; | 
|  | } | 
|  |  | 
|  | struct hostent * | 
|  | _hf_gethtbyname2(const char *name, int af, struct getnamaddr *info) | 
|  | { | 
|  | struct hostent *hp, hent; | 
|  | char *buf, *ptr; | 
|  | size_t len, anum, num, i; | 
|  | FILE *hf; | 
|  | char *aliases[MAXALIASES]; | 
|  | char *addr_ptrs[MAXADDRS]; | 
|  |  | 
|  | _DIAGASSERT(name != NULL); | 
|  |  | 
|  | 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 = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, | 
|  | info->he); | 
|  | if (hp == NULL) { | 
|  | if (*info->he == NETDB_INTERNAL && errno == ENOSPC) { | 
|  | goto nospc; // glibc compatibility. | 
|  | } | 
|  | 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) { | 
|  | hent.h_addrtype = af = hp->h_addrtype; | 
|  | hent.h_length = hp->h_length; | 
|  |  | 
|  | HENT_SCOPY(hent.h_name, hp->h_name, ptr, len); | 
|  | for (anum = 0; hp->h_aliases[anum]; anum++) { | 
|  | if (anum >= MAXALIASES) | 
|  | goto nospc; | 
|  | HENT_SCOPY(aliases[anum], hp->h_aliases[anum], | 
|  | ptr, len); | 
|  | } | 
|  | ptr = (void *)ALIGN(ptr); | 
|  | if ((size_t)(ptr - buf) >= info->buflen) | 
|  | goto nospc; | 
|  | } | 
|  |  | 
|  | if (num >= MAXADDRS) | 
|  | goto nospc; | 
|  | HENT_COPY(addr_ptrs[num], hp->h_addr_list[0], hp->h_length, ptr, | 
|  | len); | 
|  | num++; | 
|  | } | 
|  | endhostent_r(&hf); | 
|  |  | 
|  | if (num == 0) { | 
|  | *info->he = HOST_NOT_FOUND; | 
|  | free(buf); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | hp = info->hp; | 
|  | ptr = info->buf; | 
|  | len = info->buflen; | 
|  |  | 
|  | hp->h_addrtype = hent.h_addrtype; | 
|  | hp->h_length = hent.h_length; | 
|  |  | 
|  | HENT_ARRAY(hp->h_aliases, anum, ptr, len); | 
|  | HENT_ARRAY(hp->h_addr_list, num, ptr, len); | 
|  |  | 
|  | for (i = 0; i < num; i++) | 
|  | HENT_COPY(hp->h_addr_list[i], addr_ptrs[i], hp->h_length, ptr, | 
|  | len); | 
|  | hp->h_addr_list[num] = NULL; | 
|  |  | 
|  | HENT_SCOPY(hp->h_name, hent.h_name, ptr, len); | 
|  |  | 
|  | for (i = 0; i < anum; i++) | 
|  | HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len); | 
|  | hp->h_aliases[anum] = NULL; | 
|  |  | 
|  | free(buf); | 
|  | return hp; | 
|  | nospc: | 
|  | *info->he = NETDB_INTERNAL; | 
|  | free(buf); | 
|  | errno = ENOSPC; | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /*ARGSUSED*/ | 
|  | int | 
|  | _hf_gethtbyaddr(void *rv, void *cb_data, va_list ap) | 
|  | { | 
|  | struct hostent *hp; | 
|  | const unsigned char *addr; | 
|  | struct getnamaddr *info = rv; | 
|  | FILE *hf; | 
|  |  | 
|  | _DIAGASSERT(rv != NULL); | 
|  |  | 
|  | addr = va_arg(ap, unsigned char *); | 
|  | info->hp->h_length = va_arg(ap, int); | 
|  | info->hp->h_addrtype = va_arg(ap, int); | 
|  |  | 
|  | hf = NULL; | 
|  | sethostent_r(&hf); | 
|  | if (hf == NULL) { | 
|  | *info->he = NETDB_INTERNAL; | 
|  | return NS_UNAVAIL; | 
|  | } | 
|  | while ((hp = netbsd_gethostent_r(hf, info->hp, info->buf, info->buflen, | 
|  | info->he)) != NULL) | 
|  | if (!memcmp(hp->h_addr_list[0], addr, (size_t)hp->h_length)) | 
|  | break; | 
|  | endhostent_r(&hf); | 
|  |  | 
|  | if (hp == NULL) { | 
|  | if (errno == ENOSPC) return NS_UNAVAIL; // glibc compatibility. | 
|  | *info->he = HOST_NOT_FOUND; | 
|  | return NS_NOTFOUND; | 
|  | } | 
|  | return NS_SUCCESS; | 
|  | } |