Пример #1
0
struct servent *
getservbyport_r(int port, const char *proto, struct servent *result,
	char *buffer, int buflen)
{
	struct netconfig *nconf;
	struct	nss_netdirbyaddr_in nssin;
	union	nss_netdirbyaddr_out nssout;
	int neterr;

	if ((nconf = __rpc_getconfip("udp")) == NULL &&
	    (nconf = __rpc_getconfip("tcp")) == NULL) {
		return ((struct servent *)NULL);
	}
	nssin.op_t = NSS_SERV;
	nssin.arg.nss.serv.port = port;
	nssin.arg.nss.serv.proto = proto;
	nssin.arg.nss.serv.buf = buffer;
	nssin.arg.nss.serv.buflen = buflen;

	nssout.nss.serv = result;

	/*
	 * We pass in nconf and let the implementation of this long-named func
	 * decide whether to use the switch based on nc_nlookups.
	 */
	neterr = _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

	(void) freenetconfigent(nconf);
	if (neterr != ND_OK) {
		return ((struct servent *)NULL);
	}
	return (nssout.nss.serv);
}
Пример #2
0
/*
 * Remove the mapping between program, version and port.
 * Calls the pmap service remotely to do the un-mapping.
 */
bool_t
pmap_unset(u_long program, u_long version)
{
	struct netconfig *nconf;
	bool_t udp_rslt = FALSE;
	bool_t tcp_rslt = FALSE;

	nconf = __rpc_getconfip("udp");
	if (nconf != NULL) {
		udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
		    nconf);
		freenetconfigent(nconf);
	}
	nconf = __rpc_getconfip("tcp");
	if (nconf != NULL) {
		tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
		    nconf);
		freenetconfigent(nconf);
	}
	/*
	 * XXX: The call may still succeed even if only one of the
	 * calls succeeded.  This was the best that could be
	 * done for backward compatibility.
	 */
	return (tcp_rslt || udp_rslt);
}
Пример #3
0
bool_t
pmap_set(u_long program, u_long version, int protocol, int port)
{
	bool_t rslt;
	struct netbuf *na;
	struct netconfig *nconf;
	char buf[32];

	if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) {
		return (FALSE);
	}
	nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp");
	if (nconf == NULL) {
		return (FALSE);
	}
	snprintf(buf, sizeof buf, "0.0.0.0.%d.%d", 
	    (((u_int32_t)port) >> 8) & 0xff, port & 0xff);
	na = uaddr2taddr(nconf, buf);
	if (na == NULL) {
		freenetconfigent(nconf);
		return (FALSE);
	}
	rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na);
	free(na);
	freenetconfigent(nconf);
	return (rslt);
}
Пример #4
0
/*
 * Create the client des authentication object. Obsoleted by
 * authdes_seccreate().
 */
AUTH *
authdes_create(char *servername, uint_t window, struct sockaddr_in *syncaddr,
	des_block *ckey)
{
	char *hostname = NULL;

	if (syncaddr) {
		/*
		 * Change addr to hostname, because that is the way
		 * new interface takes it.
		 */
		struct netconfig *nconf;
		struct netbuf nb_syncaddr;
		struct nd_hostservlist *hlist;
		AUTH *nauth;
		int fd;
		struct t_info tinfo;

		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL)
			goto fallback;

		/* Transform sockaddr_in to netbuf */
		if ((fd = t_open(nconf->nc_device, O_RDWR, &tinfo)) == -1) {
			(void) freenetconfigent(nconf);
			goto fallback;
		}
		(void) t_close(fd);
		nb_syncaddr.maxlen = nb_syncaddr.len =
			__rpc_get_a_size(tinfo.addr);
		nb_syncaddr.buf = (char *)syncaddr;
		if (netdir_getbyaddr(nconf, &hlist, &nb_syncaddr)) {
			(void) freenetconfigent(nconf);
			goto fallback;
		}
		if (hlist && hlist->h_cnt > 0 && hlist->h_hostservs)
			hostname = hlist->h_hostservs->h_host;
		nauth = authdes_seccreate(servername, window, hostname, ckey);
		(void) netdir_free((char *)hlist, ND_HOSTSERVLIST);
		(void) freenetconfigent(nconf);
		return (nauth);
	}
fallback:
	return (authdes_seccreate(servername, window, hostname, ckey));
}
Пример #5
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, const char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sccsin;

	_DIAGASSERT(netid != NULL);

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sccsin, 0, sizeof sccsin);
	sccsin.sin_family = AF_INET;
	(void)bindresvport(fd, &sccsin);

	switch (nconf->nc_semantics) {
	case NC_TPI_COTS:
	case NC_TPI_COTS_ORD:
		if (listen(fd, SOMAXCONN) == -1) {
			(void) syslog(LOG_ERR,
			    "svc%s_create: listen(2) failed: %s",
			    netid, strerror(errno));
			(void) freenetconfigent(nconf);
			goto out;
		}
		break;
	default:
		break;
	}

	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL)
		goto out;
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return svc;
out:
	if (madefd)
		(void) close(fd);
	return NULL;
}
Пример #6
0
bool pmap_set(u_long program, u_long version, int protocol, int port)
{
	bool rslt;
	struct netbuf *na;
	struct netconfig *nconf;
	char buf[32];

	if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP))
		return (false);
	nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp");
	if (nconf == NULL)
		return (false);
	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
		snprintf(buf, sizeof(buf), "0.0.0.0.%d.%d",
			 (((u_int32_t) port) >> 8) & 0xff, port & 0xff);
	} else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
Пример #7
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, uint_t sendsize, uint_t recvsize, char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	int res;

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = t_open(nconf->nc_device, O_RDWR, NULL);
		if (fd == -1) {
			char errorstr[100];

			__tli_sys_strerror(errorstr, sizeof (errorstr),
					t_errno, errno);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection : %s", netid,
				    errorstr);
			(void) freenetconfigent(nconf);
			return (NULL);
		}
		madefd = TRUE;
	}

	res = __rpc_bindresvport(fd, NULL, &port, 8);
	svc = svc_tli_create(fd, nconf, NULL,
				sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL) {
		if (madefd)
			(void) t_close(fd);
		return (NULL);
	}
	if (res == -1)
		/* LINTED pointer cast */
		port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return (svc);
}
Пример #8
0
/*
 * A common server create routine
 */
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
{
	struct netconfig *nconf;
	SVCXPRT *svc;
	int madefd = FALSE;
	int port;
	struct sockaddr_in sin;

	if ((nconf = __rpc_getconfip(netid)) == NULL) {
		(void) syslog(LOG_ERR, "Could not get %s transport", netid);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1) {
			(void) freenetconfigent(nconf);
			(void) syslog(LOG_ERR,
			"svc%s_create: could not open connection", netid);
			return (NULL);
		}
		madefd = TRUE;
	}

	memset(&sin, 0, sizeof sin);
	sin.sin_family = AF_INET;
	bindresvport(fd, &sin);
	_listen(fd, SOMAXCONN);
	svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
	(void) freenetconfigent(nconf);
	if (svc == NULL) {
		if (madefd)
			(void)_close(fd);
		return (NULL);
	}
	port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
	svc->xp_port = ntohs(port);
	return (svc);
}
Пример #9
0
/*
 * A common clnt create routine
 */
static CLIENT *
clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
	int *sockp, u_int sendsz, u_int recvsz, const char *tp)
{
	CLIENT *cl;
	int madefd = FALSE;
	int fd;
	struct netconfig *nconf;
	struct netbuf bindaddr;

	_DIAGASSERT(raddr != NULL);
	_DIAGASSERT(sockp != NULL);
	_DIAGASSERT(tp != NULL);

	fd = *sockp;

	mutex_lock(&rpcsoc_lock);
	if ((nconf = __rpc_getconfip(tp)) == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
		mutex_unlock(&rpcsoc_lock);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = __rpc_nconf2fd(nconf);
		if (fd == -1)
			goto syserror;
		madefd = TRUE;
	}

	if (raddr->sin_port == 0) {
		u_int proto;
		u_short sport;

		mutex_unlock(&rpcsoc_lock);	/* pmap_getport is recursive */
		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
		sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
		    proto);
		if (sport == 0) {
			goto err;
		}
		raddr->sin_port = htons(sport);
		mutex_lock(&rpcsoc_lock);	/* pmap_getport is recursive */
	}

	/* Transform sockaddr_in to netbuf */
	bindaddr.maxlen = bindaddr.len =  sizeof (struct sockaddr_in);
	bindaddr.buf = raddr;

	(void)bindresvport(fd, NULL);
	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
				sendsz, recvsz);
	if (cl) {
		if (madefd == TRUE) {
			/*
			 * The fd should be closed while destroying the handle.
			 */
			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
			*sockp = fd;
		}
		(void) freenetconfigent(nconf);
		mutex_unlock(&rpcsoc_lock);
		return (cl);
	}
	goto err;

syserror:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;

err:	if (madefd == TRUE)
		(void) close(fd);
	(void) freenetconfigent(nconf);
	mutex_unlock(&rpcsoc_lock);
	return (NULL);
}
Пример #10
0
/*
 * A common clnt create routine
 */
static CLIENT *
clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers,
	int *sockp, uint_t sendsz, uint_t recvsz, char *tp)
{
	CLIENT *cl;
	int madefd = FALSE;
	int fd = *sockp;
	struct t_info tinfo;
	struct netconfig *nconf;
	int port;
	struct netbuf bindaddr;
	bool_t locked = TRUE;

	(void) mutex_lock(&rpcsoc_lock);
	if ((nconf = __rpc_getconfip(tp)) == NULL) {
		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
		(void) mutex_unlock(&rpcsoc_lock);
		return (NULL);
	}
	if (fd == RPC_ANYSOCK) {
		fd = t_open(nconf->nc_device, O_RDWR, &tinfo);
		if (fd == -1)
			goto syserror;
		RPC_RAISEFD(fd);
		madefd = TRUE;
	} else {
		if (t_getinfo(fd, &tinfo) == -1)
			goto syserror;
	}

	if (raddr->sin_port == 0) {
		uint_t proto;
		ushort_t sport;

		/* pmap_getport is recursive */
		(void) mutex_unlock(&rpcsoc_lock);
		proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
		sport = pmap_getport(raddr, prog, vers, proto);
		if (sport == 0) {
			locked = FALSE;
			goto err;
		}
		raddr->sin_port = htons(sport);
		/* pmap_getport is recursive */
		(void) mutex_lock(&rpcsoc_lock);
	}

	/* Transform sockaddr_in to netbuf */
	bindaddr.maxlen = bindaddr.len =  __rpc_get_a_size(tinfo.addr);
	bindaddr.buf = (char *)raddr;

	(void) __rpc_bindresvport(fd, NULL, &port, 0);
	cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
				sendsz, recvsz);
	if (cl) {
		if (madefd == TRUE) {
			/*
			 * The fd should be closed while destroying the handle.
			 */
			(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
			*sockp = fd;
		}
		(void) freenetconfigent(nconf);
		(void) mutex_unlock(&rpcsoc_lock);
		return (cl);
	}
	goto err;

syserror:
	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
	rpc_createerr.cf_error.re_errno = errno;
	rpc_createerr.cf_error.re_terrno = t_errno;

err:	if (madefd == TRUE)
		(void) t_close(fd);
	(void) freenetconfigent(nconf);
	if (locked == TRUE)
		(void) mutex_unlock(&rpcsoc_lock);
	return (NULL);
}
Пример #11
0
/*
 * This is the IPv6 interface for "gethostbyaddr".
 */
struct hostent *
getipnodebyaddr(const void *src, size_t len, int type, int *error_num)
{
	struct in6_addr *addr6 = 0;
	struct in_addr *addr4 = 0;
	nss_XbyY_buf_t *buf = 0;
	nss_XbyY_buf_t *res = 0;
	struct netconfig *nconf;
	struct hostent *hp = 0;
	struct	nss_netdirbyaddr_in nssin;
	union	nss_netdirbyaddr_out nssout;
	int neterr;
	char tmpbuf[64];

	if (type == AF_INET6) {
		if ((addr6 = (struct in6_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else if (type == AF_INET) {
		if ((addr4 = (struct in_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Specific case: query for "::"
	 */
	if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Step 1: IPv4-mapped address  or IPv4 Compat
	 */
	if ((type == AF_INET6 && len == 16) &&
	    ((IN6_IS_ADDR_V4MAPPED(addr6)) ||
	    (IN6_IS_ADDR_V4COMPAT(addr6)))) {
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			__IPv6_cleanup(buf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			(void) memcpy(tmpbuf, addr6, sizeof (*addr6));
			tmpbuf[10] = 0xffU;
			tmpbuf[11] = 0xffU;
			nssin.arg.nss.host.addr = (const char *)tmpbuf;
		} else {
			nssin.arg.nss.host.addr = (const char *)addr6;
		}
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			if (!gethostbyaddr_r(((char *)addr6) + 12,
			    sizeof (in_addr_t), AF_INET, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			/* Found one, now format it into mapped/compat addr */
			if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
				__IPv6_cleanup(buf);
				*error_num = NO_RECOVERY;
				return (NULL);
			}
			/* Convert IPv4 to mapped/compat address w/name */
			hp = res->result;
			(void) __mapv4tov6(buf->result, 0, res,
			    IN6_IS_ADDR_V4MAPPED(addr6));
			__IPv6_cleanup(buf);
			free(res);
			return (hp);
		}
		/*
		 * At this point, we'll have a v4mapped hostent. If that's
		 * what was passed in, just return. If the request was a compat,
		 * twiggle the two bytes to make the mapped address a compat.
		 */
		hp = buf->result;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			/* LINTED pointer cast */
			addr6 = (struct in6_addr *)hp->h_addr_list[0];
			addr6->s6_addr[10] = 0;
			addr6->s6_addr[11] = 0;
		}
		free(buf);
		return (hp);
	}
	/*
	 * Step 2: AF_INET, v4 lookup. Since we're going to search the
	 * ipnodes (v6) path first, we need to treat this as a v4mapped
	 * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The
	 * switch backend knows to lookup v4's (not v4mapped) from the
	 * name services.
	 */
	if (type == AF_INET) {
		struct in6_addr v4mapbuf;
		addr6 = &v4mapbuf;

		IN6_INADDR_TO_V4MAPPED(addr4, addr6);
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			hp = buf->result;
			if (!gethostbyaddr_r(src, len, type, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			free(buf);
			return (hp);
		}
		if ((hp = __mappedtov4(buf->result, error_num)) == NULL) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		__IPv6_cleanup(buf);
		return (hp);
	}
	/*
	 * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call.
	 */
	if (type == AF_INET6) {
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = len;
		nssin.arg.nss.host.type = type;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		free(buf);
		return (nssout.nss.host.hent);
	}
	/*
	 * If we got here, unknown type.
	 */
	*error_num = HOST_NOT_FOUND;
	return (NULL);
}
Пример #12
0
struct hostent *
getipnodebyname(const char *name, int af, int flags, int *error_num)
{
	struct hostent		*hp = NULL;
	nss_XbyY_buf_t		*buf4 = NULL;
	nss_XbyY_buf_t		*buf6 = NULL;
	struct netconfig	*nconf;
	struct nss_netdirbyname_in	nssin;
	union nss_netdirbyname_out	nssout;
	int			ret;
	uint_t			ipnode_bits;

	if ((nconf = __rpc_getconfip("udp")) == NULL &&
	    (nconf = __rpc_getconfip("tcp")) == NULL) {
		*error_num = NO_RECOVERY;
		return (NULL);
	}

	ipnode_bits = getipnodebyname_processflags(name, af, flags);

	/* Make sure we have something to look up. */
	if (!(ipnode_bits & (IPNODE_WANTIPV6 | IPNODE_WANTIPV4))) {
		*error_num = HOST_NOT_FOUND;
		goto cleanup;
	}

	/*
	 * Perform the requested lookups.  We always look through
	 * ipnodes first for both IPv4 and IPv6 addresses.  Depending
	 * on what was returned and what was needed, we either filter
	 * out the garbage, or ask for more using hosts.
	 */
	if (ipnode_bits & IPNODE_LOOKUPIPNODES) {
		if ((buf6 = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == NULL) {
			*error_num = NO_RECOVERY;
			goto cleanup;
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host6.name = name;
		nssin.arg.nss.host6.buf = buf6->buffer;
		nssin.arg.nss.host6.buflen = buf6->buflen;
		nssin.arg.nss.host6.af_family = af;
		nssin.arg.nss.host6.flags = flags;
		nssout.nss.host.hent = buf6->result;
		nssout.nss.host.herrno_p = error_num;
		ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
		if (ret != ND_OK) {
			__IPv6_cleanup(buf6);
			buf6 = NULL;
		} else if (ipnode_bits & IPNODE_WANTIPV4) {
			/*
			 * buf6 may have all that we need if we either
			 * only wanted IPv4 addresses if there were no
			 * IPv6 addresses returned, or if there are
			 * IPv4-mapped addresses in buf6.  If either
			 * of these are true, then there's no need to
			 * look in hosts.
			 */
			if (ipnode_bits & IPNODE_IPV4IFNOIPV6 ||
			    __find_mapped(buf6->result, 0) != 0) {
				ipnode_bits &= ~IPNODE_LOOKUPHOSTS;
			} else if (!(ipnode_bits & IPNODE_WANTIPV6)) {
				/*
				 * If all we're looking for are IPv4
				 * addresses and there are none in
				 * buf6 then buf6 is now useless.
				 */
				__IPv6_cleanup(buf6);
				buf6 = NULL;
			}
		}
	}
	if (ipnode_bits & IPNODE_LOOKUPHOSTS) {
		if ((buf4 = __IPv6_alloc(NSS_BUFLEN_HOSTS)) == NULL) {
			*error_num = NO_RECOVERY;
			goto cleanup;
		}
		nssin.op_t = NSS_HOST;
		nssin.arg.nss.host.name = name;
		nssin.arg.nss.host.buf = buf4->buffer;
		nssin.arg.nss.host.buflen = buf4->buflen;
		nssout.nss.host.hent = buf4->result;
		nssout.nss.host.herrno_p = error_num;
		ret = _get_hostserv_inetnetdir_byname(nconf, &nssin, &nssout);
		if (ret != ND_OK) {
			__IPv6_cleanup(buf4);
			buf4 = NULL;
		}
	}

	if (buf6 == NULL && buf4 == NULL) {
		*error_num = HOST_NOT_FOUND;
		goto cleanup;
	}

	/* Extract the appropriate addresses from the returned buffer(s). */
	switch (af) {
	case AF_INET6: {
		if (buf4 != NULL) {
			nss_XbyY_buf_t *mergebuf;

			/*
			 * The IPv4 results we have need to be
			 * converted to IPv4-mapped addresses,
			 * conditionally merged with the IPv6
			 * results, and the end result needs to be
			 * re-ordered.
			 */
			mergebuf = __IPv6_alloc(NSS_BUFLEN_IPNODES);
			if (mergebuf == NULL) {
				*error_num = NO_RECOVERY;
				goto cleanup;
			}
			hp = __mapv4tov6(buf4->result,
			    ((buf6 != NULL) ? buf6->result : NULL),
			    mergebuf, 1);
			if (hp != NULL)
				order_haddrlist_af(AF_INET6, hp->h_addr_list);
			else
				*error_num = NO_RECOVERY;
			free(mergebuf);
		}

		if (buf4 == NULL && buf6 != NULL) {
			hp = buf6->result;

			/*
			 * We have what we need in buf6, but we may need
			 * to filter out some addresses depending on what
			 * is being asked for.
			 */
			if (!(ipnode_bits & IPNODE_WANTIPV4))
				hp = __filter_addresses(AF_INET, buf6->result);
			else if (!(ipnode_bits & IPNODE_WANTIPV6))
				hp = __filter_addresses(AF_INET6, buf6->result);

			/*
			 * We've been asked to unmap v4 addresses. This
			 * situation implies IPNODE_WANTIPV4 and
			 * !IPNODE_WANTIPV6.
			 */
			if (hp != NULL && (ipnode_bits & IPNODE_UNMAP)) {
				/*
				 * Just set hp to a new value, cleanup: will
				 * free the old one
				 */
				hp = __mappedtov4(hp, error_num);
			} else if (hp == NULL)
				*error_num = NO_ADDRESS;
		}

		break;
	}

	case AF_INET:
		/* We could have results in buf6 or buf4, not both */
		if (buf6 != NULL) {
			/*
			 * Extract the IPv4-mapped addresses from buf6
			 * into hp.
			 */
			hp = __mappedtov4(buf6->result, error_num);
		} else {
			/* We have what we need in buf4. */
			hp = buf4->result;
			if (ipnode_bits & IPNODE_LITERAL) {
				/*
				 * There is a special case here for literal
				 * IPv4 address strings.  The hosts
				 * front-end sets h_aliases to a one
				 * element array containing a single NULL
				 * pointer (in ndaddr2hent()), while
				 * getipnodebyname() requires h_aliases to
				 * be a NULL pointer itself.  We're not
				 * going to change the front-end since it
				 * needs to remain backward compatible for
				 * gethostbyname() and friends.  Just set
				 * h_aliases to NULL here instead.
				 */
				hp->h_aliases = NULL;
			}
		}

		break;

	default:
		break;
	}

cleanup:
	/*
	 * Free the memory we allocated, but make sure we don't free
	 * the memory we're returning to the caller.
	 */
	if (buf6 != NULL) {
		if (buf6->result == hp)
			buf6->result = NULL;
		__IPv6_cleanup(buf6);
	}
	if (buf4 != NULL) {
		if (buf4->result == hp)
			buf4->result = NULL;
		__IPv6_cleanup(buf4);
	}
	(void) freenetconfigent(nconf);

	return (hp);
}