Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / bind / irs / nis_ho.c
blob5f86a004f2b5132cc27cba5de6453361ec9913a4
1 /*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996,1999 by Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: nis_ho.c,v 1.2.2.2 2004/03/09 09:17:33 marka Exp $";
20 #endif /* LIBC_SCCS and not lint */
22 /* Imports */
24 #include "port_before.h"
26 #ifndef WANT_IRS_NIS
27 static int __bind_irs_nis_unneeded;
28 #else
30 #include <sys/types.h>
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <arpa/nameser.h>
36 #ifdef T_NULL
37 #undef T_NULL /* Silence re-definition warning of T_NULL. */
38 #endif
39 #include <rpc/rpc.h>
40 #include <rpc/xdr.h>
41 #include <rpcsvc/yp_prot.h>
42 #include <rpcsvc/ypclnt.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <stdlib.h>
47 #include <netdb.h>
48 #include <resolv.h>
49 #include <stdio.h>
50 #include <string.h>
52 #include <isc/memcluster.h>
53 #include <irs.h>
55 #include "port_after.h"
57 #include "irs_p.h"
58 #include "nis_p.h"
60 /* Definitions */
62 #define MAXALIASES 35
63 #define MAXADDRS 35
65 #if PACKETSZ > 1024
66 #define MAXPACKET PACKETSZ
67 #else
68 #define MAXPACKET 1024
69 #endif
71 struct pvt {
72 int needrewind;
73 char * nis_domain;
74 char * curkey_data;
75 int curkey_len;
76 char * curval_data;
77 int curval_len;
78 struct hostent host;
79 char * h_addr_ptrs[MAXADDRS + 1];
80 char * host_aliases[MAXALIASES + 1];
81 char hostbuf[8*1024];
82 u_char host_addr[16]; /* IPv4 or IPv6 */
83 struct __res_state *res;
84 void (*free_res)(void *);
87 enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
89 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
90 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
91 static /*const*/ char hosts_byname[] = "hosts.byname";
92 static /*const*/ char hosts_byaddr[] = "hosts.byaddr";
93 static /*const*/ char ipnode_byname[] = "ipnode.byname";
94 static /*const*/ char ipnode_byaddr[] = "ipnode.byaddr";
95 static /*const*/ char yp_multi[] = "YP_MULTI_";
97 /* Forwards */
99 static void ho_close(struct irs_ho *this);
100 static struct hostent * ho_byname(struct irs_ho *this, const char *name);
101 static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
102 int af);
103 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
104 int len, int af);
105 static struct hostent * ho_next(struct irs_ho *this);
106 static void ho_rewind(struct irs_ho *this);
107 static void ho_minimize(struct irs_ho *this);
108 static struct __res_state * ho_res_get(struct irs_ho *this);
109 static void ho_res_set(struct irs_ho *this,
110 struct __res_state *res,
111 void (*free_res)(void *));
112 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
113 const struct addrinfo *pai);
115 static struct hostent * makehostent(struct irs_ho *this);
116 static void nisfree(struct pvt *, enum do_what);
117 static int init(struct irs_ho *this);
119 /* Public */
121 struct irs_ho *
122 irs_nis_ho(struct irs_acc *this) {
123 struct irs_ho *ho;
124 struct pvt *pvt;
126 if (!(pvt = memget(sizeof *pvt))) {
127 errno = ENOMEM;
128 return (NULL);
130 memset(pvt, 0, sizeof *pvt);
131 if (!(ho = memget(sizeof *ho))) {
132 memput(pvt, sizeof *pvt);
133 errno = ENOMEM;
134 return (NULL);
136 memset(ho, 0x5e, sizeof *ho);
137 pvt->needrewind = 1;
138 pvt->nis_domain = ((struct nis_p *)this->private)->domain;
139 ho->private = pvt;
140 ho->close = ho_close;
141 ho->byname = ho_byname;
142 ho->byname2 = ho_byname2;
143 ho->byaddr = ho_byaddr;
144 ho->next = ho_next;
145 ho->rewind = ho_rewind;
146 ho->minimize = ho_minimize;
147 ho->res_set = ho_res_set;
148 ho->res_get = ho_res_get;
149 ho->addrinfo = ho_addrinfo;
150 return (ho);
153 /* Methods */
155 static void
156 ho_close(struct irs_ho *this) {
157 struct pvt *pvt = (struct pvt *)this->private;
159 ho_minimize(this);
160 nisfree(pvt, do_all);
161 if (pvt->res && pvt->free_res)
162 (*pvt->free_res)(pvt->res);
163 memput(pvt, sizeof *pvt);
164 memput(this, sizeof *this);
167 static struct hostent *
168 ho_byname(struct irs_ho *this, const char *name) {
169 struct pvt *pvt = (struct pvt *)this->private;
170 struct hostent *hp;
172 if (init(this) == -1)
173 return (NULL);
175 if (pvt->res->options & RES_USE_INET6) {
176 hp = ho_byname2(this, name, AF_INET6);
177 if (hp)
178 return (hp);
180 return (ho_byname2(this, name, AF_INET));
183 static struct hostent *
184 ho_byname2(struct irs_ho *this, const char *name, int af) {
185 struct pvt *pvt = (struct pvt *)this->private;
186 int r;
187 char *tmp;
189 UNUSED(af);
191 if (init(this) == -1)
192 return (NULL);
194 nisfree(pvt, do_val);
196 strcpy(pvt->hostbuf, yp_multi);
197 strncat(pvt->hostbuf, name, sizeof(pvt->hostbuf) - sizeof(yp_multi));
198 pvt->hostbuf[sizeof(pvt->hostbuf) - 1] = '\0';
199 for (r = sizeof(yp_multi) - 1; pvt->hostbuf[r] != '\0'; r++)
200 if (isupper((unsigned char)pvt->hostbuf[r]))
201 tolower(pvt->hostbuf[r]);
203 tmp = pvt->hostbuf;
204 r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
205 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
206 if (r != 0) {
207 tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
208 r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
209 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
211 if (r != 0) {
212 tmp = pvt->hostbuf;
213 r = yp_match(pvt->nis_domain, hosts_byname, tmp,
214 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
216 if (r != 0) {
217 tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
218 r = yp_match(pvt->nis_domain, hosts_byname, tmp,
219 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
221 if (r != 0) {
222 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
223 return (NULL);
225 return (makehostent(this));
228 static struct hostent *
229 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
230 struct pvt *pvt = (struct pvt *)this->private;
231 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
232 const u_char *uaddr = addr;
233 int r;
235 if (init(this) == -1)
236 return (NULL);
238 if (af == AF_INET6 && len == IN6ADDRSZ &&
239 (!memcmp(uaddr, mapped, sizeof mapped) ||
240 !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
241 /* Unmap. */
242 addr = (const u_char *)addr + sizeof mapped;
243 uaddr += sizeof mapped;
244 af = AF_INET;
245 len = INADDRSZ;
247 if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) {
248 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
249 return (NULL);
251 nisfree(pvt, do_val);
252 r = yp_match(pvt->nis_domain, ipnode_byaddr, tmp, strlen(tmp),
253 &pvt->curval_data, &pvt->curval_len);
254 if (r != 0)
255 r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp),
256 &pvt->curval_data, &pvt->curval_len);
257 if (r != 0) {
258 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
259 return (NULL);
261 return (makehostent(this));
264 static struct hostent *
265 ho_next(struct irs_ho *this) {
266 struct pvt *pvt = (struct pvt *)this->private;
267 struct hostent *rval;
268 int r;
270 if (init(this) == -1)
271 return (NULL);
273 do {
274 if (pvt->needrewind) {
275 nisfree(pvt, do_all);
276 r = yp_first(pvt->nis_domain, hosts_byaddr,
277 &pvt->curkey_data, &pvt->curkey_len,
278 &pvt->curval_data, &pvt->curval_len);
279 pvt->needrewind = 0;
280 } else {
281 char *newkey_data;
282 int newkey_len;
284 nisfree(pvt, do_val);
285 r = yp_next(pvt->nis_domain, hosts_byaddr,
286 pvt->curkey_data, pvt->curkey_len,
287 &newkey_data, &newkey_len,
288 &pvt->curval_data, &pvt->curval_len);
289 nisfree(pvt, do_key);
290 pvt->curkey_data = newkey_data;
291 pvt->curkey_len = newkey_len;
293 if (r != 0) {
294 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
295 return (NULL);
297 rval = makehostent(this);
298 } while (rval == NULL);
299 return (rval);
302 static void
303 ho_rewind(struct irs_ho *this) {
304 struct pvt *pvt = (struct pvt *)this->private;
306 pvt->needrewind = 1;
309 static void
310 ho_minimize(struct irs_ho *this) {
311 struct pvt *pvt = (struct pvt *)this->private;
313 if (pvt->res)
314 res_nclose(pvt->res);
317 static struct __res_state *
318 ho_res_get(struct irs_ho *this) {
319 struct pvt *pvt = (struct pvt *)this->private;
321 if (!pvt->res) {
322 struct __res_state *res;
323 res = (struct __res_state *)malloc(sizeof *res);
324 if (!res) {
325 errno = ENOMEM;
326 return (NULL);
328 memset(res, 0, sizeof *res);
329 ho_res_set(this, res, free);
332 return (pvt->res);
335 static void
336 ho_res_set(struct irs_ho *this, struct __res_state *res,
337 void (*free_res)(void *)) {
338 struct pvt *pvt = (struct pvt *)this->private;
340 if (pvt->res && pvt->free_res) {
341 res_nclose(pvt->res);
342 (*pvt->free_res)(pvt->res);
345 pvt->res = res;
346 pvt->free_res = free_res;
349 struct nis_res_target {
350 struct nis_res_target *next;
351 int family;
354 /* XXX */
355 extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
356 const struct addrinfo *pai));
358 static struct addrinfo *
359 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
361 struct pvt *pvt = (struct pvt *)this->private;
362 struct hostent *hp;
363 struct nis_res_target q, q2, *p;
364 struct addrinfo sentinel, *cur;
366 memset(&q, 0, sizeof(q2));
367 memset(&q2, 0, sizeof(q2));
368 memset(&sentinel, 0, sizeof(sentinel));
369 cur = &sentinel;
371 switch(pai->ai_family) {
372 case AF_UNSPEC: /* INET6 then INET4 */
373 q.family = AF_INET6;
374 q.next = &q2;
375 q2.family = AF_INET;
376 break;
377 case AF_INET6:
378 q.family = AF_INET6;
379 break;
380 case AF_INET:
381 q.family = AF_INET;
382 break;
383 default:
384 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /* ??? */
385 return(NULL);
388 for (p = &q; p; p = p->next) {
389 struct addrinfo *ai;
391 hp = (*this->byname2)(this, name, p->family);
392 if (hp == NULL) {
393 /* byname2 should've set an appropriate error */
394 continue;
396 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
397 (hp->h_addr_list[0] == NULL)) {
398 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
399 continue;
401 ai = hostent2addrinfo(hp, pai);
402 if (ai) {
403 cur->ai_next = ai;
404 while (cur && cur->ai_next)
405 cur = cur->ai_next;
409 if (sentinel.ai_next == NULL)
410 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
412 return(sentinel.ai_next);
415 /* Private */
418 ipnodes:
419 ::1 localhost
420 127.0.0.1 localhost
421 1.2.3.4 FOO bar
422 1.2.6.4 FOO bar
423 1.2.6.5 host
425 ipnodes.byname:
426 YP_MULTI_localhost ::1,127.0.0.1 localhost
427 YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
428 YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
429 host 1.2.6.5 host
431 hosts.byname:
432 localhost 127.0.0.1 localhost
433 host 1.2.6.5 host
434 YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
435 YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
438 static struct hostent *
439 makehostent(struct irs_ho *this) {
440 struct pvt *pvt = (struct pvt *)this->private;
441 static const char spaces[] = " \t";
442 char *cp, **q, *p, *comma, *ap;
443 int af = 0, len = 0;
444 int multi = 0;
445 int addr = 0;
447 p = pvt->curval_data;
448 if ((cp = strpbrk(p, "#\n")) != NULL)
449 *cp = '\0';
450 if (!(cp = strpbrk(p, spaces)))
451 return (NULL);
452 *cp++ = '\0';
453 ap = pvt->hostbuf;
454 do {
455 if ((comma = strchr(p, ',')) != NULL) {
456 *comma++ = '\0';
457 multi = 1;
459 if ((ap + IN6ADDRSZ) > (pvt->hostbuf + sizeof(pvt->hostbuf)))
460 break;
461 if ((pvt->res->options & RES_USE_INET6) &&
462 inet_pton(AF_INET6, p, ap) > 0) {
463 af = AF_INET6;
464 len = IN6ADDRSZ;
465 } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) {
466 if (pvt->res->options & RES_USE_INET6) {
467 map_v4v6_address((char*)pvt->host_addr, ap);
468 af = AF_INET6;
469 len = IN6ADDRSZ;
470 } else {
471 af = AF_INET;
472 len = INADDRSZ;
474 } else {
475 if (!multi)
476 return (NULL);
477 continue;
479 if (addr < MAXADDRS) {
480 pvt->h_addr_ptrs[addr++] = ap;
481 pvt->h_addr_ptrs[addr] = NULL;
482 ap += len;
484 } while ((p = comma) != NULL);
485 if (ap == pvt->hostbuf)
486 return (NULL);
487 pvt->host.h_addr_list = pvt->h_addr_ptrs;
488 pvt->host.h_length = len;
489 pvt->host.h_addrtype = af;
490 cp += strspn(cp, spaces);
491 pvt->host.h_name = cp;
492 q = pvt->host.h_aliases = pvt->host_aliases;
493 if ((cp = strpbrk(cp, spaces)) != NULL)
494 *cp++ = '\0';
495 while (cp && *cp) {
496 if (*cp == ' ' || *cp == '\t') {
497 cp++;
498 continue;
500 if (q < &pvt->host_aliases[MAXALIASES])
501 *q++ = cp;
502 if ((cp = strpbrk(cp, spaces)) != NULL)
503 *cp++ = '\0';
505 *q = NULL;
506 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
507 return (&pvt->host);
510 static void
511 nisfree(struct pvt *pvt, enum do_what do_what) {
512 if ((do_what & do_key) && pvt->curkey_data) {
513 free(pvt->curkey_data);
514 pvt->curkey_data = NULL;
516 if ((do_what & do_val) && pvt->curval_data) {
517 free(pvt->curval_data);
518 pvt->curval_data = NULL;
522 static int
523 init(struct irs_ho *this) {
524 struct pvt *pvt = (struct pvt *)this->private;
526 if (!pvt->res && !ho_res_get(this))
527 return (-1);
528 if (((pvt->res->options & RES_INIT) == 0) &&
529 res_ninit(pvt->res) == -1)
530 return (-1);
531 return (0);
533 #endif /*WANT_IRS_NIS*/