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.5 2005/04/27 04:56:32 sra Exp $";
20 #endif /* LIBC_SCCS and not lint */
24 #include "port_before.h"
27 static int __bind_irs_nis_unneeded
;
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>
37 #undef T_NULL /* Silence re-definition warning of T_NULL. */
41 #include <rpcsvc/yp_prot.h>
42 #include <rpcsvc/ypclnt.h>
52 #include <isc/memcluster.h>
55 #include "port_after.h"
66 #define MAXPACKET PACKETSZ
68 #define MAXPACKET 1024
79 char * h_addr_ptrs
[MAXADDRS
+ 1];
80 char * host_aliases
[MAXALIASES
+ 1];
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_";
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
,
103 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
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);
122 irs_nis_ho(struct irs_acc
*this) {
126 if (!(pvt
= memget(sizeof *pvt
))) {
130 memset(pvt
, 0, sizeof *pvt
);
131 if (!(ho
= memget(sizeof *ho
))) {
132 memput(pvt
, sizeof *pvt
);
136 memset(ho
, 0x5e, sizeof *ho
);
138 pvt
->nis_domain
= ((struct nis_p
*)this->private)->domain
;
140 ho
->close
= ho_close
;
141 ho
->byname
= ho_byname
;
142 ho
->byname2
= ho_byname2
;
143 ho
->byaddr
= ho_byaddr
;
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
;
156 ho_close(struct irs_ho
*this) {
157 struct pvt
*pvt
= (struct pvt
*)this->private;
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;
172 if (init(this) == -1)
175 if (pvt
->res
->options
& RES_USE_INET6
) {
176 hp
= ho_byname2(this, name
, AF_INET6
);
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;
191 if (init(this) == -1)
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
]);
204 r
= yp_match(pvt
->nis_domain
, ipnode_byname
, tmp
,
205 strlen(tmp
), &pvt
->curval_data
, &pvt
->curval_len
);
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
);
213 r
= yp_match(pvt
->nis_domain
, hosts_byname
, tmp
,
214 strlen(tmp
), &pvt
->curval_data
, &pvt
->curval_len
);
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
);
222 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
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
;
235 if (init(this) == -1)
238 if (af
== AF_INET6
&& len
== IN6ADDRSZ
&&
239 (!memcmp(uaddr
, mapped
, sizeof mapped
) ||
240 !memcmp(uaddr
, tunnelled
, sizeof tunnelled
))) {
242 addr
= (const u_char
*)addr
+ sizeof mapped
;
243 uaddr
+= sizeof mapped
;
247 if (inet_ntop(af
, uaddr
, tmp
, sizeof tmp
) == NULL
) {
248 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
251 nisfree(pvt
, do_val
);
252 r
= yp_match(pvt
->nis_domain
, ipnode_byaddr
, tmp
, strlen(tmp
),
253 &pvt
->curval_data
, &pvt
->curval_len
);
255 r
= yp_match(pvt
->nis_domain
, hosts_byaddr
, tmp
, strlen(tmp
),
256 &pvt
->curval_data
, &pvt
->curval_len
);
258 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
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
;
270 if (init(this) == -1)
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
);
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
;
294 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
297 rval
= makehostent(this);
298 } while (rval
== NULL
);
303 ho_rewind(struct irs_ho
*this) {
304 struct pvt
*pvt
= (struct pvt
*)this->private;
310 ho_minimize(struct irs_ho
*this) {
311 struct pvt
*pvt
= (struct pvt
*)this->private;
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;
322 struct __res_state
*res
;
323 res
= (struct __res_state
*)malloc(sizeof *res
);
328 memset(res
, 0, sizeof *res
);
329 ho_res_set(this, res
, free
);
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
);
346 pvt
->free_res
= free_res
;
349 struct nis_res_target
{
350 struct nis_res_target
*next
;
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;
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
));
371 switch(pai
->ai_family
) {
372 case AF_UNSPEC
: /*%< INET6 then INET4 */
384 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
); /*%< ??? */
388 for (p
= &q
; p
; p
= p
->next
) {
391 hp
= (*this->byname2
)(this, name
, p
->family
);
393 /* byname2 should've set an appropriate error */
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
);
401 ai
= hostent2addrinfo(hp
, pai
);
404 while (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
);
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
432 localhost 127.0.0.1 localhost
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
;
447 p
= pvt
->curval_data
;
448 if ((cp
= strpbrk(p
, "#\n")) != NULL
)
450 if (!(cp
= strpbrk(p
, spaces
)))
455 if ((comma
= strchr(p
, ',')) != NULL
) {
459 if ((ap
+ IN6ADDRSZ
) > (pvt
->hostbuf
+ sizeof(pvt
->hostbuf
)))
461 if ((pvt
->res
->options
& RES_USE_INET6
) &&
462 inet_pton(AF_INET6
, p
, ap
) > 0) {
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
);
479 if (addr
< MAXADDRS
) {
480 pvt
->h_addr_ptrs
[addr
++] = ap
;
481 pvt
->h_addr_ptrs
[addr
] = NULL
;
484 } while ((p
= comma
) != NULL
);
485 if (ap
== pvt
->hostbuf
)
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
)
496 if (*cp
== ' ' || *cp
== '\t') {
500 if (q
< &pvt
->host_aliases
[MAXALIASES
])
502 if ((cp
= strpbrk(cp
, spaces
)) != NULL
)
506 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
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
;
523 init(struct irs_ho
*this) {
524 struct pvt
*pvt
= (struct pvt
*)this->private;
526 if (!pvt
->res
&& !ho_res_get(this))
528 if (((pvt
->res
->options
& RES_INIT
) == 0) &&
529 res_ninit(pvt
->res
) == -1)
533 #endif /*WANT_IRS_NIS*/