Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / libbind / dist / irs / nis_ho.c
blob3704b6d311fbaf1bb6d8d2a1a64335c810726da7
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996,1999 by Internet Software Consortium.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid[] = "Id: nis_ho.c,v 1.5 2005/04/27 04:56:32 sra Exp";
22 #endif /* LIBC_SCCS and not lint */
24 /* Imports */
26 #include "port_before.h"
28 #ifndef WANT_IRS_NIS
29 static int __bind_irs_nis_unneeded;
30 #else
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <arpa/nameser.h>
38 #ifdef T_NULL
39 #undef T_NULL /* Silence re-definition warning of T_NULL. */
40 #endif
41 #include <rpc/rpc.h>
42 #include <rpc/xdr.h>
43 #include <rpcsvc/yp_prot.h>
44 #include <rpcsvc/ypclnt.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <stdlib.h>
49 #include <netdb.h>
50 #include <resolv.h>
51 #include <stdio.h>
52 #include <string.h>
54 #include <isc/memcluster.h>
55 #include <irs.h>
57 #include "port_after.h"
59 #include "irs_p.h"
60 #include "nis_p.h"
62 /* Definitions */
64 #define MAXALIASES 35
65 #define MAXADDRS 35
67 #if PACKETSZ > 1024
68 #define MAXPACKET PACKETSZ
69 #else
70 #define MAXPACKET 1024
71 #endif
73 struct pvt {
74 int needrewind;
75 char * nis_domain;
76 char * curkey_data;
77 int curkey_len;
78 char * curval_data;
79 int curval_len;
80 struct hostent host;
81 char * h_addr_ptrs[MAXADDRS + 1];
82 char * host_aliases[MAXALIASES + 1];
83 char hostbuf[8*1024];
84 u_char host_addr[16]; /*%< IPv4 or IPv6 */
85 struct __res_state *res;
86 void (*free_res)(void *);
89 enum do_what { do_none = 0x0, do_key = 0x1, do_val = 0x2, do_all = 0x3 };
91 static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
92 static const u_char tunnelled[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
93 static /*const*/ char hosts_byname[] = "hosts.byname";
94 static /*const*/ char hosts_byaddr[] = "hosts.byaddr";
95 static /*const*/ char ipnode_byname[] = "ipnode.byname";
96 static /*const*/ char ipnode_byaddr[] = "ipnode.byaddr";
97 static /*const*/ char yp_multi[] = "YP_MULTI_";
99 /* Forwards */
101 static void ho_close(struct irs_ho *this);
102 static struct hostent * ho_byname(struct irs_ho *this, const char *name);
103 static struct hostent * ho_byname2(struct irs_ho *this, const char *name,
104 int af);
105 static struct hostent * ho_byaddr(struct irs_ho *this, const void *addr,
106 int len, int af);
107 static struct hostent * ho_next(struct irs_ho *this);
108 static void ho_rewind(struct irs_ho *this);
109 static void ho_minimize(struct irs_ho *this);
110 static struct __res_state * ho_res_get(struct irs_ho *this);
111 static void ho_res_set(struct irs_ho *this,
112 struct __res_state *res,
113 void (*free_res)(void *));
114 static struct addrinfo * ho_addrinfo(struct irs_ho *this, const char *name,
115 const struct addrinfo *pai);
117 static struct hostent * makehostent(struct irs_ho *this);
118 static void nisfree(struct pvt *, enum do_what);
119 static int init(struct irs_ho *this);
121 /* Public */
123 struct irs_ho *
124 irs_nis_ho(struct irs_acc *this) {
125 struct irs_ho *ho;
126 struct pvt *pvt;
128 if (!(pvt = memget(sizeof *pvt))) {
129 errno = ENOMEM;
130 return (NULL);
132 memset(pvt, 0, sizeof *pvt);
133 if (!(ho = memget(sizeof *ho))) {
134 memput(pvt, sizeof *pvt);
135 errno = ENOMEM;
136 return (NULL);
138 memset(ho, 0x5e, sizeof *ho);
139 pvt->needrewind = 1;
140 pvt->nis_domain = ((struct nis_p *)this->private)->domain;
141 ho->private = pvt;
142 ho->close = ho_close;
143 ho->byname = ho_byname;
144 ho->byname2 = ho_byname2;
145 ho->byaddr = ho_byaddr;
146 ho->next = ho_next;
147 ho->rewind = ho_rewind;
148 ho->minimize = ho_minimize;
149 ho->res_set = ho_res_set;
150 ho->res_get = ho_res_get;
151 ho->addrinfo = ho_addrinfo;
152 return (ho);
155 /* Methods */
157 static void
158 ho_close(struct irs_ho *this) {
159 struct pvt *pvt = (struct pvt *)this->private;
161 ho_minimize(this);
162 nisfree(pvt, do_all);
163 if (pvt->res && pvt->free_res)
164 (*pvt->free_res)(pvt->res);
165 memput(pvt, sizeof *pvt);
166 memput(this, sizeof *this);
169 static struct hostent *
170 ho_byname(struct irs_ho *this, const char *name) {
171 struct pvt *pvt = (struct pvt *)this->private;
172 struct hostent *hp;
174 if (init(this) == -1)
175 return (NULL);
177 if (pvt->res->options & RES_USE_INET6) {
178 hp = ho_byname2(this, name, AF_INET6);
179 if (hp)
180 return (hp);
182 return (ho_byname2(this, name, AF_INET));
185 static struct hostent *
186 ho_byname2(struct irs_ho *this, const char *name, int af) {
187 struct pvt *pvt = (struct pvt *)this->private;
188 int r;
189 char *tmp;
191 UNUSED(af);
193 if (init(this) == -1)
194 return (NULL);
196 nisfree(pvt, do_val);
198 strcpy(pvt->hostbuf, yp_multi);
199 strncat(pvt->hostbuf, name, sizeof(pvt->hostbuf) - sizeof(yp_multi));
200 pvt->hostbuf[sizeof(pvt->hostbuf) - 1] = '\0';
201 for (r = sizeof(yp_multi) - 1; pvt->hostbuf[r] != '\0'; r++)
202 if (isupper((unsigned char)pvt->hostbuf[r]))
203 tolower(pvt->hostbuf[r]);
205 tmp = pvt->hostbuf;
206 r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
207 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
208 if (r != 0) {
209 tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
210 r = yp_match(pvt->nis_domain, ipnode_byname, tmp,
211 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
213 if (r != 0) {
214 tmp = pvt->hostbuf;
215 r = yp_match(pvt->nis_domain, hosts_byname, tmp,
216 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
218 if (r != 0) {
219 tmp = pvt->hostbuf + sizeof(yp_multi) - 1;
220 r = yp_match(pvt->nis_domain, hosts_byname, tmp,
221 strlen(tmp), &pvt->curval_data, &pvt->curval_len);
223 if (r != 0) {
224 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
225 return (NULL);
227 return (makehostent(this));
230 static struct hostent *
231 ho_byaddr(struct irs_ho *this, const void *addr, int len, int af) {
232 struct pvt *pvt = (struct pvt *)this->private;
233 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
234 const u_char *uaddr = addr;
235 int r;
237 if (init(this) == -1)
238 return (NULL);
240 if (af == AF_INET6 && len == IN6ADDRSZ &&
241 (!memcmp(uaddr, mapped, sizeof mapped) ||
242 !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
243 /* Unmap. */
244 addr = (const u_char *)addr + sizeof mapped;
245 uaddr += sizeof mapped;
246 af = AF_INET;
247 len = INADDRSZ;
249 if (inet_ntop(af, uaddr, tmp, sizeof tmp) == NULL) {
250 RES_SET_H_ERRNO(pvt->res, NETDB_INTERNAL);
251 return (NULL);
253 nisfree(pvt, do_val);
254 r = yp_match(pvt->nis_domain, ipnode_byaddr, tmp, strlen(tmp),
255 &pvt->curval_data, &pvt->curval_len);
256 if (r != 0)
257 r = yp_match(pvt->nis_domain, hosts_byaddr, tmp, strlen(tmp),
258 &pvt->curval_data, &pvt->curval_len);
259 if (r != 0) {
260 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
261 return (NULL);
263 return (makehostent(this));
266 static struct hostent *
267 ho_next(struct irs_ho *this) {
268 struct pvt *pvt = (struct pvt *)this->private;
269 struct hostent *rval;
270 int r;
272 if (init(this) == -1)
273 return (NULL);
275 do {
276 if (pvt->needrewind) {
277 nisfree(pvt, do_all);
278 r = yp_first(pvt->nis_domain, hosts_byaddr,
279 &pvt->curkey_data, &pvt->curkey_len,
280 &pvt->curval_data, &pvt->curval_len);
281 pvt->needrewind = 0;
282 } else {
283 char *newkey_data;
284 int newkey_len;
286 nisfree(pvt, do_val);
287 r = yp_next(pvt->nis_domain, hosts_byaddr,
288 pvt->curkey_data, pvt->curkey_len,
289 &newkey_data, &newkey_len,
290 &pvt->curval_data, &pvt->curval_len);
291 nisfree(pvt, do_key);
292 pvt->curkey_data = newkey_data;
293 pvt->curkey_len = newkey_len;
295 if (r != 0) {
296 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
297 return (NULL);
299 rval = makehostent(this);
300 } while (rval == NULL);
301 return (rval);
304 static void
305 ho_rewind(struct irs_ho *this) {
306 struct pvt *pvt = (struct pvt *)this->private;
308 pvt->needrewind = 1;
311 static void
312 ho_minimize(struct irs_ho *this) {
313 struct pvt *pvt = (struct pvt *)this->private;
315 if (pvt->res)
316 res_nclose(pvt->res);
319 static struct __res_state *
320 ho_res_get(struct irs_ho *this) {
321 struct pvt *pvt = (struct pvt *)this->private;
323 if (!pvt->res) {
324 struct __res_state *res;
325 res = (struct __res_state *)malloc(sizeof *res);
326 if (!res) {
327 errno = ENOMEM;
328 return (NULL);
330 memset(res, 0, sizeof *res);
331 ho_res_set(this, res, free);
334 return (pvt->res);
337 static void
338 ho_res_set(struct irs_ho *this, struct __res_state *res,
339 void (*free_res)(void *)) {
340 struct pvt *pvt = (struct pvt *)this->private;
342 if (pvt->res && pvt->free_res) {
343 res_nclose(pvt->res);
344 (*pvt->free_res)(pvt->res);
347 pvt->res = res;
348 pvt->free_res = free_res;
351 struct nis_res_target {
352 struct nis_res_target *next;
353 int family;
356 /* XXX */
357 extern struct addrinfo *hostent2addrinfo __P((struct hostent *,
358 const struct addrinfo *pai));
360 static struct addrinfo *
361 ho_addrinfo(struct irs_ho *this, const char *name, const struct addrinfo *pai)
363 struct pvt *pvt = (struct pvt *)this->private;
364 struct hostent *hp;
365 struct nis_res_target q, q2, *p;
366 struct addrinfo sentinel, *cur;
368 memset(&q, 0, sizeof(q2));
369 memset(&q2, 0, sizeof(q2));
370 memset(&sentinel, 0, sizeof(sentinel));
371 cur = &sentinel;
373 switch(pai->ai_family) {
374 case AF_UNSPEC: /*%< INET6 then INET4 */
375 q.family = AF_INET6;
376 q.next = &q2;
377 q2.family = AF_INET;
378 break;
379 case AF_INET6:
380 q.family = AF_INET6;
381 break;
382 case AF_INET:
383 q.family = AF_INET;
384 break;
385 default:
386 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY); /*%< ??? */
387 return(NULL);
390 for (p = &q; p; p = p->next) {
391 struct addrinfo *ai;
393 hp = (*this->byname2)(this, name, p->family);
394 if (hp == NULL) {
395 /* byname2 should've set an appropriate error */
396 continue;
398 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
399 (hp->h_addr_list[0] == NULL)) {
400 RES_SET_H_ERRNO(pvt->res, NO_RECOVERY);
401 continue;
403 ai = hostent2addrinfo(hp, pai);
404 if (ai) {
405 cur->ai_next = ai;
406 while (cur && cur->ai_next)
407 cur = cur->ai_next;
411 if (sentinel.ai_next == NULL)
412 RES_SET_H_ERRNO(pvt->res, HOST_NOT_FOUND);
414 return(sentinel.ai_next);
417 /* Private */
420 ipnodes:
421 ::1 localhost
422 127.0.0.1 localhost
423 1.2.3.4 FOO bar
424 1.2.6.4 FOO bar
425 1.2.6.5 host
427 ipnodes.byname:
428 YP_MULTI_localhost ::1,127.0.0.1 localhost
429 YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
430 YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
431 host 1.2.6.5 host
433 hosts.byname:
434 localhost 127.0.0.1 localhost
435 host 1.2.6.5 host
436 YP_MULTI_foo 1.2.3.4,1.2.6.4 FOO bar
437 YP_MULTI_bar 1.2.3.4,1.2.6.4 FOO bar
440 static struct hostent *
441 makehostent(struct irs_ho *this) {
442 struct pvt *pvt = (struct pvt *)this->private;
443 static const char spaces[] = " \t";
444 char *cp, **q, *p, *comma, *ap;
445 int af = 0, len = 0;
446 int multi = 0;
447 int addr = 0;
449 p = pvt->curval_data;
450 if ((cp = strpbrk(p, "#\n")) != NULL)
451 *cp = '\0';
452 if (!(cp = strpbrk(p, spaces)))
453 return (NULL);
454 *cp++ = '\0';
455 ap = pvt->hostbuf;
456 do {
457 if ((comma = strchr(p, ',')) != NULL) {
458 *comma++ = '\0';
459 multi = 1;
461 if ((ap + IN6ADDRSZ) > (pvt->hostbuf + sizeof(pvt->hostbuf)))
462 break;
463 if ((pvt->res->options & RES_USE_INET6) &&
464 inet_pton(AF_INET6, p, ap) > 0) {
465 af = AF_INET6;
466 len = IN6ADDRSZ;
467 } else if (inet_pton(AF_INET, p, pvt->host_addr) > 0) {
468 if (pvt->res->options & RES_USE_INET6) {
469 map_v4v6_address((char*)pvt->host_addr, ap);
470 af = AF_INET6;
471 len = IN6ADDRSZ;
472 } else {
473 af = AF_INET;
474 len = INADDRSZ;
476 } else {
477 if (!multi)
478 return (NULL);
479 continue;
481 if (addr < MAXADDRS) {
482 pvt->h_addr_ptrs[addr++] = ap;
483 pvt->h_addr_ptrs[addr] = NULL;
484 ap += len;
486 } while ((p = comma) != NULL);
487 if (ap == pvt->hostbuf)
488 return (NULL);
489 pvt->host.h_addr_list = pvt->h_addr_ptrs;
490 pvt->host.h_length = len;
491 pvt->host.h_addrtype = af;
492 cp += strspn(cp, spaces);
493 pvt->host.h_name = cp;
494 q = pvt->host.h_aliases = pvt->host_aliases;
495 if ((cp = strpbrk(cp, spaces)) != NULL)
496 *cp++ = '\0';
497 while (cp && *cp) {
498 if (*cp == ' ' || *cp == '\t') {
499 cp++;
500 continue;
502 if (q < &pvt->host_aliases[MAXALIASES])
503 *q++ = cp;
504 if ((cp = strpbrk(cp, spaces)) != NULL)
505 *cp++ = '\0';
507 *q = NULL;
508 RES_SET_H_ERRNO(pvt->res, NETDB_SUCCESS);
509 return (&pvt->host);
512 static void
513 nisfree(struct pvt *pvt, enum do_what do_what) {
514 if ((do_what & do_key) && pvt->curkey_data) {
515 free(pvt->curkey_data);
516 pvt->curkey_data = NULL;
518 if ((do_what & do_val) && pvt->curval_data) {
519 free(pvt->curval_data);
520 pvt->curval_data = NULL;
524 static int
525 init(struct irs_ho *this) {
526 struct pvt *pvt = (struct pvt *)this->private;
528 if (!pvt->res && !ho_res_get(this))
529 return (-1);
530 if (((pvt->res->options & RES_INIT) == 0) &&
531 res_ninit(pvt->res) == -1)
532 return (-1);
533 return (0);
535 #endif /*WANT_IRS_NIS*/
537 /*! \file */