Use BIND's resolver in libc.
[dragonfly.git] / lib / libc / net / gethostbynis.c
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  * $FreeBSD: src/lib/libc/net/gethostbynis.c,v 1.28 2006/05/12 15:37:23 ume Exp $
26  * $DragonFly: src/lib/libc/net/gethostbynis.c,v 1.4 2005/11/13 02:04:47 swildner Exp $
27  */
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
51 static 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
163 static 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
180 static 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*() */
202 struct 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
229 struct 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
256 int
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                 *h_errnop = statp->res_h_errno;
292                 return (NS_NOTFOUND);
293         }
294         *((struct hostent **)rval) = hptr;
295         return (NS_SUCCESS);
296 #else
297         *((struct hostent **)rval) = NULL;
298         return (NS_UNAVAIL);
299 #endif
300 }
301
302 int
303 _nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
304 {
305 #ifdef YP
306         const void *addr;
307         socklen_t len;
308         int af;
309         char *buffer;
310         size_t buflen;
311         int *errnop, *h_errnop;
312         struct hostent *hptr, he;
313         struct hostent_data *hed;
314         res_state statp;
315
316         addr = va_arg(ap, const void *);
317         len = va_arg(ap, socklen_t);
318         af = va_arg(ap, int);
319         hptr = va_arg(ap, struct hostent *);
320         buffer = va_arg(ap, char *);
321         buflen = va_arg(ap, size_t);
322         errnop = va_arg(ap, int *);
323         h_errnop = va_arg(ap, int *);
324
325         *((struct hostent **)rval) = NULL;
326
327         statp = __res_state();
328         if ((hed = __hostent_data_init()) == NULL) {
329                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
330                 *h_errnop = statp->res_h_errno;
331                 return (NS_NOTFOUND);
332         }
333
334         if (_gethostbynisaddr_r(addr, len, af, &he, hed) != 0) {
335                 *h_errnop = statp->res_h_errno;
336                 return (NS_NOTFOUND);
337         }
338         if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
339                 *h_errnop = statp->res_h_errno;
340                 return (NS_NOTFOUND);
341         }
342         *((struct hostent **)rval) = hptr;
343         return (NS_SUCCESS);
344 #else
345         *((struct hostent **)rval) = NULL;
346         return (NS_UNAVAIL);
347 #endif
348 }