1/*-
2 * Copyright (c) 1994, Garrett Wollman
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <arpa/inet.h>
33#include <arpa/nameser.h>
34#include <netdb.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <ctype.h>
38#include <errno.h>
39#include <string.h>
40#include <stdarg.h>
41#include <nsswitch.h>
42#include <resolv.h>		/* XXX */
43#ifdef YP
44#include <rpc/rpc.h>
45#include <rpcsvc/yp_prot.h>
46#include <rpcsvc/ypclnt.h>
47#endif
48#include "netdb_private.h"
49
50#ifdef YP
51static int
52_gethostbynis(const char *name, char *map, int af, struct hostent *he,
53    struct hostent_data *hed)
54{
55	char *p, *bp, *ep;
56	char *cp, **q;
57	char *result;
58	int resultlen, size, addrok = 0;
59	char ypbuf[YPMAXRECORD + 2];
60	res_state statp;
61
62	statp = __res_state();
63	switch(af) {
64	case AF_INET:
65		size = NS_INADDRSZ;
66		break;
67	case AF_INET6:
68		size = NS_IN6ADDRSZ;
69		break;
70	default:
71		errno = EAFNOSUPPORT;
72		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
73		return (-1);
74	}
75
76	if (hed->yp_domain == (char *)NULL)
77		if (yp_get_default_domain (&hed->yp_domain)) {
78			RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
79			return (-1);
80		}
81
82	if (yp_match(hed->yp_domain, map, name, strlen(name), &result,
83	    &resultlen)) {
84		RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
85		return (-1);
86	}
87
88	/* avoid potential memory leak */
89	bcopy((char *)result, (char *)&ypbuf, resultlen);
90	ypbuf[resultlen] = '\0';
91	free(result);
92	result = (char *)&ypbuf;
93
94	if ((cp = index(result, '\n')))
95		*cp = '\0';
96
97	cp = strpbrk(result, " \t");
98	*cp++ = '\0';
99	he->h_addr_list = hed->h_addr_ptrs;
100	he->h_addr = (char *)hed->host_addr;
101	switch (af) {
102	case AF_INET:
103		addrok = inet_aton(result, (struct in_addr *)hed->host_addr);
104		if (addrok != 1)
105			break;
106		if (statp->options & RES_USE_INET6) {
107			_map_v4v6_address((char *)hed->host_addr,
108			    (char *)hed->host_addr);
109			af = AF_INET6;
110			size = NS_IN6ADDRSZ;
111		}
112		break;
113	case AF_INET6:
114		addrok = inet_pton(af, result, hed->host_addr);
115		break;
116	}
117	if (addrok != 1) {
118		RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
119		return (-1);
120	}
121	he->h_addr_list[1] = NULL;
122	he->h_length = size;
123	he->h_addrtype = af;
124	while (*cp == ' ' || *cp == '\t')
125		cp++;
126	bp = hed->hostbuf;
127	ep = hed->hostbuf + sizeof hed->hostbuf;
128	he->h_name = bp;
129	q = he->h_aliases = hed->host_aliases;
130	p = strpbrk(cp, " \t");
131	if (p != NULL)
132		*p++ = '\0';
133	size = strlen(cp) + 1;
134	if (ep - bp < size) {
135		RES_SET_H_ERRNO(statp, NO_RECOVERY);
136		return (-1);
137	}
138	strlcpy(bp, cp, ep - bp);
139	bp += size;
140	cp = p;
141	while (cp && *cp) {
142		if (*cp == ' ' || *cp == '\t') {
143			cp++;
144			continue;
145		}
146		if (q >= &hed->host_aliases[_MAXALIASES - 1])
147			break;
148		p = strpbrk(cp, " \t");
149		if (p != NULL)
150			*p++ = '\0';
151		size = strlen(cp) + 1;
152		if (ep - bp < size)
153			break;
154		strlcpy(bp, cp, ep - bp);
155		*q++ = bp;
156		bp += size;
157		cp = p;
158	}
159	*q = NULL;
160	return (0);
161}
162
163static int
164_gethostbynisname_r(const char *name, int af, struct hostent *he,
165    struct hostent_data *hed)
166{
167	char *map;
168
169	switch (af) {
170	case AF_INET:
171		map = "hosts.byname";
172		break;
173	default:
174		map = "ipnodes.byname";
175		break;
176	}
177	return (_gethostbynis(name, map, af, he, hed));
178}
179
180static int
181_gethostbynisaddr_r(const void *addr, socklen_t len, int af,
182    struct hostent *he, struct hostent_data *hed)
183{
184	char *map;
185	char numaddr[46];
186
187	switch (af) {
188	case AF_INET:
189		map = "hosts.byaddr";
190		break;
191	default:
192		map = "ipnodes.byaddr";
193		break;
194	}
195	if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
196		return (-1);
197	return (_gethostbynis(numaddr, map, af, he, hed));
198}
199#endif /* YP */
200
201/* XXX _gethostbynisname/_gethostbynisaddr only used by getipnodeby*() */
202struct hostent *
203_gethostbynisname(const char *name, int af)
204{
205#ifdef YP
206	struct hostent *he;
207	struct hostent_data *hed;
208	u_long oresopt;
209	int error;
210	res_state statp;
211
212	statp = __res_state();
213	if ((he = __hostent_init()) == NULL ||
214	    (hed = __hostent_data_init()) == NULL) {
215		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
216		return (NULL);
217	}
218
219	oresopt = statp->options;
220	statp->options &= ~RES_USE_INET6;
221	error = _gethostbynisname_r(name, af, he, hed);
222	statp->options = oresopt;
223	return (error == 0) ? he : NULL;
224#else
225	return (NULL);
226#endif
227}
228
229struct hostent *
230_gethostbynisaddr(const void *addr, socklen_t len, int af)
231{
232#ifdef YP
233	struct hostent *he;
234	struct hostent_data *hed;
235	u_long oresopt;
236	int error;
237	res_state statp;
238
239	statp = __res_state();
240	if ((he = __hostent_init()) == NULL ||
241	    (hed = __hostent_data_init()) == NULL) {
242		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
243		return (NULL);
244	}
245
246	oresopt = statp->options;
247	statp->options &= ~RES_USE_INET6;
248	error = _gethostbynisaddr_r(addr, len, af, he, hed);
249	statp->options = oresopt;
250	return (error == 0) ? he : NULL;
251#else
252	return (NULL);
253#endif
254}
255
256int
257_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
258{
259#ifdef YP
260	const char *name;
261	int af;
262	char *buffer;
263	size_t buflen;
264	int *errnop, *h_errnop;
265	struct hostent *hptr, he;
266	struct hostent_data *hed;
267	res_state statp;
268
269	name = va_arg(ap, const char *);
270	af = va_arg(ap, int);
271	hptr = va_arg(ap, struct hostent *);
272	buffer = va_arg(ap, char *);
273	buflen = va_arg(ap, size_t);
274	errnop = va_arg(ap, int *);
275	h_errnop = va_arg(ap, int *);
276
277	*((struct hostent **)rval) = NULL;
278
279	statp = __res_state();
280	if ((hed = __hostent_data_init()) == NULL) {
281		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
282		*h_errnop = statp->res_h_errno;
283		return (NS_NOTFOUND);
284	}
285
286	if (_gethostbynisname_r(name, af, &he, hed) != 0) {
287		*h_errnop = statp->res_h_errno;
288		return (NS_NOTFOUND);
289	}
290	if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
291		*errnop = errno;
292		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
293		*h_errnop = statp->res_h_errno;
294		return (NS_RETURN);
295	}
296	*((struct hostent **)rval) = hptr;
297	return (NS_SUCCESS);
298#else
299	*((struct hostent **)rval) = NULL;
300	return (NS_UNAVAIL);
301#endif
302}
303
304int
305_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
306{
307#ifdef YP
308	const void *addr;
309	socklen_t len;
310	int af;
311	char *buffer;
312	size_t buflen;
313	int *errnop, *h_errnop;
314	struct hostent *hptr, he;
315	struct hostent_data *hed;
316	res_state statp;
317
318	addr = va_arg(ap, const void *);
319	len = va_arg(ap, socklen_t);
320	af = va_arg(ap, int);
321	hptr = va_arg(ap, struct hostent *);
322	buffer = va_arg(ap, char *);
323	buflen = va_arg(ap, size_t);
324	errnop = va_arg(ap, int *);
325	h_errnop = va_arg(ap, int *);
326
327	*((struct hostent **)rval) = NULL;
328
329	statp = __res_state();
330	if ((hed = __hostent_data_init()) == NULL) {
331		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
332		*h_errnop = statp->res_h_errno;
333		return (NS_NOTFOUND);
334	}
335
336	if (_gethostbynisaddr_r(addr, len, af, &he, hed) != 0) {
337		*h_errnop = statp->res_h_errno;
338		return (NS_NOTFOUND);
339	}
340	if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
341		*errnop = errno;
342		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
343		*h_errnop = statp->res_h_errno;
344		return (NS_RETURN);
345	}
346	*((struct hostent **)rval) = hptr;
347	return (NS_SUCCESS);
348#else
349	*((struct hostent **)rval) = NULL;
350	return (NS_UNAVAIL);
351#endif
352}
353