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 */
26 #include "port_before.h"
29 static int __bind_irs_nis_unneeded
;
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>
39 #undef T_NULL /* Silence re-definition warning of T_NULL. */
43 #include <rpcsvc/yp_prot.h>
44 #include <rpcsvc/ypclnt.h>
54 #include <isc/memcluster.h>
57 #include "port_after.h"
68 #define MAXPACKET PACKETSZ
70 #define MAXPACKET 1024
81 char * h_addr_ptrs
[MAXADDRS
+ 1];
82 char * host_aliases
[MAXALIASES
+ 1];
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_";
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
,
105 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
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);
124 irs_nis_ho(struct irs_acc
*this) {
128 if (!(pvt
= memget(sizeof *pvt
))) {
132 memset(pvt
, 0, sizeof *pvt
);
133 if (!(ho
= memget(sizeof *ho
))) {
134 memput(pvt
, sizeof *pvt
);
138 memset(ho
, 0x5e, sizeof *ho
);
140 pvt
->nis_domain
= ((struct nis_p
*)this->private)->domain
;
142 ho
->close
= ho_close
;
143 ho
->byname
= ho_byname
;
144 ho
->byname2
= ho_byname2
;
145 ho
->byaddr
= ho_byaddr
;
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
;
158 ho_close(struct irs_ho
*this) {
159 struct pvt
*pvt
= (struct pvt
*)this->private;
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;
174 if (init(this) == -1)
177 if (pvt
->res
->options
& RES_USE_INET6
) {
178 hp
= ho_byname2(this, name
, AF_INET6
);
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;
193 if (init(this) == -1)
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
]);
206 r
= yp_match(pvt
->nis_domain
, ipnode_byname
, tmp
,
207 strlen(tmp
), &pvt
->curval_data
, &pvt
->curval_len
);
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
);
215 r
= yp_match(pvt
->nis_domain
, hosts_byname
, tmp
,
216 strlen(tmp
), &pvt
->curval_data
, &pvt
->curval_len
);
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
);
224 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
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
;
237 if (init(this) == -1)
240 if (af
== AF_INET6
&& len
== IN6ADDRSZ
&&
241 (!memcmp(uaddr
, mapped
, sizeof mapped
) ||
242 !memcmp(uaddr
, tunnelled
, sizeof tunnelled
))) {
244 addr
= (const u_char
*)addr
+ sizeof mapped
;
245 uaddr
+= sizeof mapped
;
249 if (inet_ntop(af
, uaddr
, tmp
, sizeof tmp
) == NULL
) {
250 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
253 nisfree(pvt
, do_val
);
254 r
= yp_match(pvt
->nis_domain
, ipnode_byaddr
, tmp
, strlen(tmp
),
255 &pvt
->curval_data
, &pvt
->curval_len
);
257 r
= yp_match(pvt
->nis_domain
, hosts_byaddr
, tmp
, strlen(tmp
),
258 &pvt
->curval_data
, &pvt
->curval_len
);
260 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
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
;
272 if (init(this) == -1)
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
);
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
;
296 RES_SET_H_ERRNO(pvt
->res
, HOST_NOT_FOUND
);
299 rval
= makehostent(this);
300 } while (rval
== NULL
);
305 ho_rewind(struct irs_ho
*this) {
306 struct pvt
*pvt
= (struct pvt
*)this->private;
312 ho_minimize(struct irs_ho
*this) {
313 struct pvt
*pvt
= (struct pvt
*)this->private;
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;
324 struct __res_state
*res
;
325 res
= (struct __res_state
*)malloc(sizeof *res
);
330 memset(res
, 0, sizeof *res
);
331 ho_res_set(this, res
, free
);
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
);
348 pvt
->free_res
= free_res
;
351 struct nis_res_target
{
352 struct nis_res_target
*next
;
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;
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
));
373 switch(pai
->ai_family
) {
374 case AF_UNSPEC
: /*%< INET6 then INET4 */
386 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
); /*%< ??? */
390 for (p
= &q
; p
; p
= p
->next
) {
393 hp
= (*this->byname2
)(this, name
, p
->family
);
395 /* byname2 should've set an appropriate error */
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
);
403 ai
= hostent2addrinfo(hp
, pai
);
406 while (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
);
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
434 localhost 127.0.0.1 localhost
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
;
449 p
= pvt
->curval_data
;
450 if ((cp
= strpbrk(p
, "#\n")) != NULL
)
452 if (!(cp
= strpbrk(p
, spaces
)))
457 if ((comma
= strchr(p
, ',')) != NULL
) {
461 if ((ap
+ IN6ADDRSZ
) > (pvt
->hostbuf
+ sizeof(pvt
->hostbuf
)))
463 if ((pvt
->res
->options
& RES_USE_INET6
) &&
464 inet_pton(AF_INET6
, p
, ap
) > 0) {
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
);
481 if (addr
< MAXADDRS
) {
482 pvt
->h_addr_ptrs
[addr
++] = ap
;
483 pvt
->h_addr_ptrs
[addr
] = NULL
;
486 } while ((p
= comma
) != NULL
);
487 if (ap
== pvt
->hostbuf
)
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
)
498 if (*cp
== ' ' || *cp
== '\t') {
502 if (q
< &pvt
->host_aliases
[MAXALIASES
])
504 if ((cp
= strpbrk(cp
, spaces
)) != NULL
)
508 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
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
;
525 init(struct irs_ho
*this) {
526 struct pvt
*pvt
= (struct pvt
*)this->private;
528 if (!pvt
->res
&& !ho_res_get(this))
530 if (((pvt
->res
->options
& RES_INIT
) == 0) &&
531 res_ninit(pvt
->res
) == -1)
535 #endif /*WANT_IRS_NIS*/