2 * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: addr_families.c 22039 2007-11-10 11:47:35Z lha $"
39 struct addr_operations
{
41 krb5_address_type atype
;
42 size_t max_sockaddr_size
;
43 krb5_error_code (*sockaddr2addr
)(const struct sockaddr
*, krb5_address
*);
44 krb5_error_code (*sockaddr2port
)(const struct sockaddr
*, int16_t *);
45 void (*addr2sockaddr
)(const krb5_address
*, struct sockaddr
*,
46 krb5_socklen_t
*sa_size
, int port
);
47 void (*h_addr2sockaddr
)(const char *, struct sockaddr
*, krb5_socklen_t
*, int);
48 krb5_error_code (*h_addr2addr
)(const char *, krb5_address
*);
49 krb5_boolean (*uninteresting
)(const struct sockaddr
*);
50 void (*anyaddr
)(struct sockaddr
*, krb5_socklen_t
*, int);
51 int (*print_addr
)(const krb5_address
*, char *, size_t);
52 int (*parse_addr
)(krb5_context
, const char*, krb5_address
*);
53 int (*order_addr
)(krb5_context
, const krb5_address
*, const krb5_address
*);
54 int (*free_addr
)(krb5_context
, krb5_address
*);
55 int (*copy_addr
)(krb5_context
, const krb5_address
*, krb5_address
*);
56 int (*mask_boundary
)(krb5_context
, const krb5_address
*, unsigned long,
57 krb5_address
*, krb5_address
*);
61 * AF_INET - aka IPv4 implementation
64 static krb5_error_code
65 ipv4_sockaddr2addr (const struct sockaddr
*sa
, krb5_address
*a
)
67 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
70 a
->addr_type
= KRB5_ADDRESS_INET
;
71 memcpy (buf
, &sin4
->sin_addr
, 4);
72 return krb5_data_copy(&a
->address
, buf
, 4);
75 static krb5_error_code
76 ipv4_sockaddr2port (const struct sockaddr
*sa
, int16_t *port
)
78 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
80 *port
= sin4
->sin_port
;
85 ipv4_addr2sockaddr (const krb5_address
*a
,
87 krb5_socklen_t
*sa_size
,
90 struct sockaddr_in tmp
;
92 memset (&tmp
, 0, sizeof(tmp
));
93 tmp
.sin_family
= AF_INET
;
94 memcpy (&tmp
.sin_addr
, a
->address
.data
, 4);
96 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
97 *sa_size
= sizeof(tmp
);
101 ipv4_h_addr2sockaddr(const char *addr
,
103 krb5_socklen_t
*sa_size
,
106 struct sockaddr_in tmp
;
108 memset (&tmp
, 0, sizeof(tmp
));
109 tmp
.sin_family
= AF_INET
;
111 tmp
.sin_addr
= *((const struct in_addr
*)addr
);
112 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
113 *sa_size
= sizeof(tmp
);
116 static krb5_error_code
117 ipv4_h_addr2addr (const char *addr
,
120 unsigned char buf
[4];
122 a
->addr_type
= KRB5_ADDRESS_INET
;
123 memcpy(buf
, addr
, 4);
124 return krb5_data_copy(&a
->address
, buf
, 4);
128 * Are there any addresses that should be considered `uninteresting'?
132 ipv4_uninteresting (const struct sockaddr
*sa
)
134 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
136 if (sin4
->sin_addr
.s_addr
== INADDR_ANY
)
143 ipv4_anyaddr (struct sockaddr
*sa
, krb5_socklen_t
*sa_size
, int port
)
145 struct sockaddr_in tmp
;
147 memset (&tmp
, 0, sizeof(tmp
));
148 tmp
.sin_family
= AF_INET
;
150 tmp
.sin_addr
.s_addr
= INADDR_ANY
;
151 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
152 *sa_size
= sizeof(tmp
);
156 ipv4_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
160 memcpy (&ia
, addr
->address
.data
, 4);
162 return snprintf (str
, len
, "IPv4:%s", inet_ntoa(ia
));
166 ipv4_parse_addr (krb5_context context
, const char *address
, krb5_address
*addr
)
171 p
= strchr(address
, ':');
174 if(strncasecmp(address
, "ip:", p
- address
) != 0 &&
175 strncasecmp(address
, "ip4:", p
- address
) != 0 &&
176 strncasecmp(address
, "ipv4:", p
- address
) != 0 &&
177 strncasecmp(address
, "inet:", p
- address
) != 0)
181 #ifdef HAVE_INET_ATON
182 if(inet_aton(p
, &a
) == 0)
184 #elif defined(HAVE_INET_ADDR)
185 a
.s_addr
= inet_addr(p
);
186 if(a
.s_addr
== INADDR_NONE
)
191 addr
->addr_type
= KRB5_ADDRESS_INET
;
192 if(krb5_data_alloc(&addr
->address
, 4) != 0)
194 _krb5_put_int(addr
->address
.data
, ntohl(a
.s_addr
), addr
->address
.length
);
199 ipv4_mask_boundary(krb5_context context
, const krb5_address
*inaddr
,
200 unsigned long len
, krb5_address
*low
, krb5_address
*high
)
203 uint32_t l
, h
, m
= 0xffffffff;
206 krb5_set_error_string(context
, "IPv4 prefix too large (%ld)", len
);
207 return KRB5_PROG_ATYPE_NOSUPP
;
211 _krb5_get_int(inaddr
->address
.data
, &ia
, inaddr
->address
.length
);
216 low
->addr_type
= KRB5_ADDRESS_INET
;
217 if(krb5_data_alloc(&low
->address
, 4) != 0)
219 _krb5_put_int(low
->address
.data
, l
, low
->address
.length
);
221 high
->addr_type
= KRB5_ADDRESS_INET
;
222 if(krb5_data_alloc(&high
->address
, 4) != 0) {
223 krb5_free_address(context
, low
);
226 _krb5_put_int(high
->address
.data
, h
, high
->address
.length
);
233 * AF_INET6 - aka IPv6 implementation
238 static krb5_error_code
239 ipv6_sockaddr2addr (const struct sockaddr
*sa
, krb5_address
*a
)
241 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
243 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)) {
244 unsigned char buf
[4];
246 a
->addr_type
= KRB5_ADDRESS_INET
;
247 #ifndef IN6_ADDR_V6_TO_V4
248 #ifdef IN6_EXTRACT_V4ADDR
249 #define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
251 #define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
254 memcpy (buf
, IN6_ADDR_V6_TO_V4(&sin6
->sin6_addr
), 4);
255 return krb5_data_copy(&a
->address
, buf
, 4);
257 a
->addr_type
= KRB5_ADDRESS_INET6
;
258 return krb5_data_copy(&a
->address
,
260 sizeof(sin6
->sin6_addr
));
264 static krb5_error_code
265 ipv6_sockaddr2port (const struct sockaddr
*sa
, int16_t *port
)
267 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
269 *port
= sin6
->sin6_port
;
274 ipv6_addr2sockaddr (const krb5_address
*a
,
276 krb5_socklen_t
*sa_size
,
279 struct sockaddr_in6 tmp
;
281 memset (&tmp
, 0, sizeof(tmp
));
282 tmp
.sin6_family
= AF_INET6
;
283 memcpy (&tmp
.sin6_addr
, a
->address
.data
, sizeof(tmp
.sin6_addr
));
284 tmp
.sin6_port
= port
;
285 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
286 *sa_size
= sizeof(tmp
);
290 ipv6_h_addr2sockaddr(const char *addr
,
292 krb5_socklen_t
*sa_size
,
295 struct sockaddr_in6 tmp
;
297 memset (&tmp
, 0, sizeof(tmp
));
298 tmp
.sin6_family
= AF_INET6
;
299 tmp
.sin6_port
= port
;
300 tmp
.sin6_addr
= *((const struct in6_addr
*)addr
);
301 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
302 *sa_size
= sizeof(tmp
);
305 static krb5_error_code
306 ipv6_h_addr2addr (const char *addr
,
309 a
->addr_type
= KRB5_ADDRESS_INET6
;
310 return krb5_data_copy(&a
->address
, addr
, sizeof(struct in6_addr
));
318 ipv6_uninteresting (const struct sockaddr
*sa
)
320 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
321 const struct in6_addr
*in6
= (const struct in6_addr
*)&sin6
->sin6_addr
;
324 IN6_IS_ADDR_LINKLOCAL(in6
)
325 || IN6_IS_ADDR_V4COMPAT(in6
);
329 ipv6_anyaddr (struct sockaddr
*sa
, krb5_socklen_t
*sa_size
, int port
)
331 struct sockaddr_in6 tmp
;
333 memset (&tmp
, 0, sizeof(tmp
));
334 tmp
.sin6_family
= AF_INET6
;
335 tmp
.sin6_port
= port
;
336 tmp
.sin6_addr
= in6addr_any
;
337 *sa_size
= sizeof(tmp
);
341 ipv6_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
343 char buf
[128], buf2
[3];
344 #ifdef HAVE_INET_NTOP
345 if(inet_ntop(AF_INET6
, addr
->address
.data
, buf
, sizeof(buf
)) == NULL
)
348 /* XXX this is pretty ugly, but better than abort() */
350 unsigned char *p
= addr
->address
.data
;
352 for(i
= 0; i
< addr
->address
.length
; i
++) {
353 snprintf(buf2
, sizeof(buf2
), "%02x", p
[i
]);
354 if(i
> 0 && (i
& 1) == 0)
355 strlcat(buf
, ":", sizeof(buf
));
356 strlcat(buf
, buf2
, sizeof(buf
));
359 return snprintf(str
, len
, "IPv6:%s", buf
);
363 ipv6_parse_addr (krb5_context context
, const char *address
, krb5_address
*addr
)
369 p
= strchr(address
, ':');
372 if(strncasecmp(address
, "ip6:", p
- address
) == 0 ||
373 strncasecmp(address
, "ipv6:", p
- address
) == 0 ||
374 strncasecmp(address
, "inet6:", p
- address
) == 0)
378 ret
= inet_pton(AF_INET6
, address
, &in6
.s6_addr
);
380 addr
->addr_type
= KRB5_ADDRESS_INET6
;
381 ret
= krb5_data_alloc(&addr
->address
, sizeof(in6
.s6_addr
));
384 memcpy(addr
->address
.data
, in6
.s6_addr
, sizeof(in6
.s6_addr
));
391 ipv6_mask_boundary(krb5_context context
, const krb5_address
*inaddr
,
392 unsigned long len
, krb5_address
*low
, krb5_address
*high
)
394 struct in6_addr addr
, laddr
, haddr
;
399 krb5_set_error_string(context
, "IPv6 prefix too large (%ld)", len
);
400 return KRB5_PROG_ATYPE_NOSUPP
;
403 if (inaddr
->address
.length
!= sizeof(addr
)) {
404 krb5_set_error_string(context
, "IPv6 addr bad length");
405 return KRB5_PROG_ATYPE_NOSUPP
;
408 memcpy(&addr
, inaddr
->address
.data
, inaddr
->address
.length
);
410 for (i
= 0; i
< 16; i
++) {
411 sub_len
= min(8, len
);
413 m
= 0xff << (8 - sub_len
);
415 laddr
.s6_addr
[i
] = addr
.s6_addr
[i
] & m
;
416 haddr
.s6_addr
[i
] = (addr
.s6_addr
[i
] & m
) | ~m
;
424 low
->addr_type
= KRB5_ADDRESS_INET6
;
425 if (krb5_data_alloc(&low
->address
, sizeof(laddr
.s6_addr
)) != 0)
427 memcpy(low
->address
.data
, laddr
.s6_addr
, sizeof(laddr
.s6_addr
));
429 high
->addr_type
= KRB5_ADDRESS_INET6
;
430 if (krb5_data_alloc(&high
->address
, sizeof(haddr
.s6_addr
)) != 0) {
431 krb5_free_address(context
, low
);
434 memcpy(high
->address
.data
, haddr
.s6_addr
, sizeof(haddr
.s6_addr
));
445 #define KRB5_ADDRESS_ARANGE (-100)
453 arange_parse_addr (krb5_context context
,
454 const char *address
, krb5_address
*addr
)
457 krb5_address low0
, high0
;
461 if(strncasecmp(address
, "RANGE:", 6) != 0)
466 p
= strrchr(address
, '/');
468 krb5_addresses addrmask
;
472 if (strlcpy(buf
, address
, sizeof(buf
)) > sizeof(buf
))
474 buf
[p
- address
] = '\0';
475 ret
= krb5_parse_address(context
, buf
, &addrmask
);
478 if(addrmask
.len
!= 1) {
479 krb5_free_addresses(context
, &addrmask
);
483 address
+= p
- address
+ 1;
485 num
= strtol(address
, &q
, 10);
486 if (q
== address
|| *q
!= '\0' || num
< 0) {
487 krb5_free_addresses(context
, &addrmask
);
491 ret
= krb5_address_prefixlen_boundary(context
, &addrmask
.val
[0], num
,
493 krb5_free_addresses(context
, &addrmask
);
498 krb5_addresses low
, high
;
500 strsep_copy(&address
, "-", buf
, sizeof(buf
));
501 ret
= krb5_parse_address(context
, buf
, &low
);
505 krb5_free_addresses(context
, &low
);
509 strsep_copy(&address
, "-", buf
, sizeof(buf
));
510 ret
= krb5_parse_address(context
, buf
, &high
);
512 krb5_free_addresses(context
, &low
);
516 if(high
.len
!= 1 && high
.val
[0].addr_type
!= low
.val
[0].addr_type
) {
517 krb5_free_addresses(context
, &low
);
518 krb5_free_addresses(context
, &high
);
522 ret
= krb5_copy_address(context
, &high
.val
[0], &high0
);
524 ret
= krb5_copy_address(context
, &low
.val
[0], &low0
);
526 krb5_free_address(context
, &high0
);
528 krb5_free_addresses(context
, &low
);
529 krb5_free_addresses(context
, &high
);
534 krb5_data_alloc(&addr
->address
, sizeof(*a
));
535 addr
->addr_type
= KRB5_ADDRESS_ARANGE
;
536 a
= addr
->address
.data
;
538 if(krb5_address_order(context
, &low0
, &high0
) < 0) {
549 arange_free (krb5_context context
, krb5_address
*addr
)
552 a
= addr
->address
.data
;
553 krb5_free_address(context
, &a
->low
);
554 krb5_free_address(context
, &a
->high
);
555 krb5_data_free(&addr
->address
);
561 arange_copy (krb5_context context
, const krb5_address
*inaddr
,
562 krb5_address
*outaddr
)
565 struct arange
*i
, *o
;
567 outaddr
->addr_type
= KRB5_ADDRESS_ARANGE
;
568 ret
= krb5_data_alloc(&outaddr
->address
, sizeof(*o
));
571 i
= inaddr
->address
.data
;
572 o
= outaddr
->address
.data
;
573 ret
= krb5_copy_address(context
, &i
->low
, &o
->low
);
575 krb5_data_free(&outaddr
->address
);
578 ret
= krb5_copy_address(context
, &i
->high
, &o
->high
);
580 krb5_free_address(context
, &o
->low
);
581 krb5_data_free(&outaddr
->address
);
588 arange_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
592 size_t l
, size
, ret_len
;
594 a
= addr
->address
.data
;
596 l
= strlcpy(str
, "RANGE:", len
);
602 ret
= krb5_print_address (&a
->low
, str
+ size
, len
- size
, &l
);
611 l
= strlcat(str
+ size
, "-", len
- size
);
618 ret
= krb5_print_address (&a
->high
, str
+ size
, len
- size
, &l
);
627 arange_order_addr(krb5_context context
,
628 const krb5_address
*addr1
,
629 const krb5_address
*addr2
)
631 int tmp1
, tmp2
, sign
;
633 const krb5_address
*a2
;
635 if(addr1
->addr_type
== KRB5_ADDRESS_ARANGE
) {
636 a
= addr1
->address
.data
;
639 } else if(addr2
->addr_type
== KRB5_ADDRESS_ARANGE
) {
640 a
= addr2
->address
.data
;
646 if(a2
->addr_type
== KRB5_ADDRESS_ARANGE
) {
647 struct arange
*b
= a2
->address
.data
;
648 tmp1
= krb5_address_order(context
, &a
->low
, &b
->low
);
651 return sign
* krb5_address_order(context
, &a
->high
, &b
->high
);
652 } else if(a2
->addr_type
== a
->low
.addr_type
) {
653 tmp1
= krb5_address_order(context
, &a
->low
, a2
);
656 tmp2
= krb5_address_order(context
, &a
->high
, a2
);
661 return sign
* (addr1
->addr_type
- addr2
->addr_type
);
666 addrport_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
669 krb5_address addr1
, addr2
;
671 size_t ret_len
= 0, l
, size
= 0;
674 sp
= krb5_storage_from_data((krb5_data
*)rk_UNCONST(&addr
->address
));
675 /* for totally obscure reasons, these are not in network byteorder */
676 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_LE
);
678 krb5_storage_seek(sp
, 2, SEEK_CUR
); /* skip first two bytes */
679 krb5_ret_address(sp
, &addr1
);
681 krb5_storage_seek(sp
, 2, SEEK_CUR
); /* skip two bytes */
682 krb5_ret_address(sp
, &addr2
);
683 krb5_storage_free(sp
);
684 if(addr2
.addr_type
== KRB5_ADDRESS_IPPORT
&& addr2
.address
.length
== 2) {
686 _krb5_get_int(addr2
.address
.data
, &value
, 2);
689 l
= strlcpy(str
, "ADDRPORT:", len
);
696 ret
= krb5_print_address(&addr1
, str
+ size
, len
- size
, &l
);
705 ret
= snprintf(str
+ size
, len
- size
, ",PORT=%u", port
);
712 static struct addr_operations at
[] = {
713 {AF_INET
, KRB5_ADDRESS_INET
, sizeof(struct sockaddr_in
),
717 ipv4_h_addr2sockaddr
,
719 ipv4_uninteresting
, ipv4_anyaddr
, ipv4_print_addr
, ipv4_parse_addr
,
720 NULL
, NULL
, NULL
, ipv4_mask_boundary
},
722 {AF_INET6
, KRB5_ADDRESS_INET6
, sizeof(struct sockaddr_in6
),
726 ipv6_h_addr2sockaddr
,
728 ipv6_uninteresting
, ipv6_anyaddr
, ipv6_print_addr
, ipv6_parse_addr
,
729 NULL
, NULL
, NULL
, ipv6_mask_boundary
} ,
731 {KRB5_ADDRESS_ADDRPORT
, KRB5_ADDRESS_ADDRPORT
, 0,
732 NULL
, NULL
, NULL
, NULL
, NULL
,
733 NULL
, NULL
, addrport_print_addr
, NULL
, NULL
, NULL
, NULL
},
734 /* fake address type */
735 {KRB5_ADDRESS_ARANGE
, KRB5_ADDRESS_ARANGE
, sizeof(struct arange
),
736 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
737 arange_print_addr
, arange_parse_addr
,
738 arange_order_addr
, arange_free
, arange_copy
}
741 static int num_addrs
= sizeof(at
) / sizeof(at
[0]);
743 static size_t max_sockaddr_size
= 0;
749 static struct addr_operations
*
752 struct addr_operations
*a
;
754 for (a
= at
; a
< at
+ num_addrs
; ++a
)
760 static struct addr_operations
*
761 find_atype(int atype
)
763 struct addr_operations
*a
;
765 for (a
= at
; a
< at
+ num_addrs
; ++a
)
766 if (atype
== a
->atype
)
772 * krb5_sockaddr2address stores a address a "struct sockaddr" sa in
773 * the krb5_address addr.
775 * @param context a Keberos context
776 * @param sa a struct sockaddr to extract the address from
777 * @param addr an Kerberos 5 address to store the address in.
779 * @return Return an error code or 0.
781 * @ingroup krb5_address
784 krb5_error_code KRB5_LIB_FUNCTION
785 krb5_sockaddr2address (krb5_context context
,
786 const struct sockaddr
*sa
, krb5_address
*addr
)
788 struct addr_operations
*a
= find_af(sa
->sa_family
);
790 krb5_set_error_string (context
, "Address family %d not supported",
792 return KRB5_PROG_ATYPE_NOSUPP
;
794 return (*a
->sockaddr2addr
)(sa
, addr
);
798 * krb5_sockaddr2port extracts a port (if possible) from a "struct
801 * @param context a Keberos context
802 * @param sa a struct sockaddr to extract the port from
803 * @param port a pointer to an int16_t store the port in.
805 * @return Return an error code or 0. Will return
806 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
808 * @ingroup krb5_address
811 krb5_error_code KRB5_LIB_FUNCTION
812 krb5_sockaddr2port (krb5_context context
,
813 const struct sockaddr
*sa
, int16_t *port
)
815 struct addr_operations
*a
= find_af(sa
->sa_family
);
817 krb5_set_error_string (context
, "Address family %d not supported",
819 return KRB5_PROG_ATYPE_NOSUPP
;
821 return (*a
->sockaddr2port
)(sa
, port
);
825 * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr
826 * and port. The argument sa_size should initially contain the size of
827 * the sa and after the call, it will contain the actual length of the
828 * address. In case of the sa is too small to fit the whole address,
829 * the up to *sa_size will be stored, and then *sa_size will be set to
830 * the required length.
832 * @param context a Keberos context
833 * @param addr the address to copy the from
834 * @param sa the struct sockaddr that will be filled in
835 * @param sa_size pointer to length of sa, and after the call, it will
836 * contain the actual length of the address.
837 * @param port set port in sa.
839 * @return Return an error code or 0. Will return
840 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
842 * @ingroup krb5_address
845 krb5_error_code KRB5_LIB_FUNCTION
846 krb5_addr2sockaddr (krb5_context context
,
847 const krb5_address
*addr
,
849 krb5_socklen_t
*sa_size
,
852 struct addr_operations
*a
= find_atype(addr
->addr_type
);
855 krb5_set_error_string (context
, "Address type %d not supported",
857 return KRB5_PROG_ATYPE_NOSUPP
;
859 if (a
->addr2sockaddr
== NULL
) {
860 krb5_set_error_string (context
,
861 "Can't convert address type %d to sockaddr",
863 return KRB5_PROG_ATYPE_NOSUPP
;
865 (*a
->addr2sockaddr
)(addr
, sa
, sa_size
, port
);
870 * krb5_max_sockaddr_size returns the max size of the .Li struct
871 * sockaddr that the Kerberos library will return.
873 * @return Return an size_t of the maximum struct sockaddr.
875 * @ingroup krb5_address
878 size_t KRB5_LIB_FUNCTION
879 krb5_max_sockaddr_size (void)
881 if (max_sockaddr_size
== 0) {
882 struct addr_operations
*a
;
884 for(a
= at
; a
< at
+ num_addrs
; ++a
)
885 max_sockaddr_size
= max(max_sockaddr_size
, a
->max_sockaddr_size
);
887 return max_sockaddr_size
;
891 * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the
892 * kerberos library thinks are uninteresting. One example are link
895 * @param sa pointer to struct sockaddr that might be interesting.
897 * @return Return a non zero for uninteresting addresses.
899 * @ingroup krb5_address
902 krb5_boolean KRB5_LIB_FUNCTION
903 krb5_sockaddr_uninteresting(const struct sockaddr
*sa
)
905 struct addr_operations
*a
= find_af(sa
->sa_family
);
906 if (a
== NULL
|| a
->uninteresting
== NULL
)
908 return (*a
->uninteresting
)(sa
);
912 * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and
913 * the "struct hostent" (see gethostbyname(3) ) h_addr_list
914 * component. The argument sa_size should initially contain the size
915 * of the sa, and after the call, it will contain the actual length of
918 * @param context a Keberos context
919 * @param af addresses
920 * @param addr address
921 * @param sa returned struct sockaddr
922 * @param sa_size size of sa
923 * @param port port to set in sa.
925 * @return Return an error code or 0.
927 * @ingroup krb5_address
930 krb5_error_code KRB5_LIB_FUNCTION
931 krb5_h_addr2sockaddr (krb5_context context
,
933 const char *addr
, struct sockaddr
*sa
,
934 krb5_socklen_t
*sa_size
,
937 struct addr_operations
*a
= find_af(af
);
939 krb5_set_error_string (context
, "Address family %d not supported", af
);
940 return KRB5_PROG_ATYPE_NOSUPP
;
942 (*a
->h_addr2sockaddr
)(addr
, sa
, sa_size
, port
);
947 * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception
948 * that it operates on a krb5_address instead of a struct sockaddr.
950 * @param context a Keberos context
951 * @param af address family
952 * @param haddr host address from struct hostent.
953 * @param addr returned krb5_address.
955 * @return Return an error code or 0.
957 * @ingroup krb5_address
960 krb5_error_code KRB5_LIB_FUNCTION
961 krb5_h_addr2addr (krb5_context context
,
963 const char *haddr
, krb5_address
*addr
)
965 struct addr_operations
*a
= find_af(af
);
967 krb5_set_error_string (context
, "Address family %d not supported", af
);
968 return KRB5_PROG_ATYPE_NOSUPP
;
970 return (*a
->h_addr2addr
)(haddr
, addr
);
974 * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to
975 * bind(2) to. The argument sa_size should initially contain the size
976 * of the sa, and after the call, it will contain the actual length
979 * @param context a Keberos context
980 * @param af address family
982 * @param sa_size lenght of sa.
983 * @param port for to fill into sa.
985 * @return Return an error code or 0.
987 * @ingroup krb5_address
990 krb5_error_code KRB5_LIB_FUNCTION
991 krb5_anyaddr (krb5_context context
,
994 krb5_socklen_t
*sa_size
,
997 struct addr_operations
*a
= find_af (af
);
1000 krb5_set_error_string (context
, "Address family %d not supported", af
);
1001 return KRB5_PROG_ATYPE_NOSUPP
;
1004 (*a
->anyaddr
)(sa
, sa_size
, port
);
1009 * krb5_print_address prints the address in addr to the string string
1010 * that have the length len. If ret_len is not NULL, it will be filled
1011 * with the length of the string if size were unlimited (not including
1014 * @param addr address to be printed
1015 * @param str pointer string to print the address into
1016 * @param len length that will fit into area pointed to by "str".
1017 * @param ret_len return length the str.
1019 * @return Return an error code or 0.
1021 * @ingroup krb5_address
1024 krb5_error_code KRB5_LIB_FUNCTION
1025 krb5_print_address (const krb5_address
*addr
,
1026 char *str
, size_t len
, size_t *ret_len
)
1028 struct addr_operations
*a
= find_atype(addr
->addr_type
);
1031 if (a
== NULL
|| a
->print_addr
== NULL
) {
1037 l
= snprintf(s
, len
, "TYPE_%d:", addr
->addr_type
);
1038 if (l
< 0 || l
>= len
)
1042 for(i
= 0; i
< addr
->address
.length
; i
++) {
1043 l
= snprintf(s
, len
, "%02x", ((char*)addr
->address
.data
)[i
]);
1044 if (l
< 0 || l
>= len
)
1053 ret
= (*a
->print_addr
)(addr
, str
, len
);
1062 * krb5_parse_address returns the resolved hostname in string to the
1063 * krb5_addresses addresses .
1065 * @param context a Keberos context
1069 * @return Return an error code or 0.
1071 * @ingroup krb5_address
1074 krb5_error_code KRB5_LIB_FUNCTION
1075 krb5_parse_address(krb5_context context
,
1077 krb5_addresses
*addresses
)
1080 struct addrinfo
*ai
, *a
;
1085 addresses
->val
= NULL
;
1087 for(i
= 0; i
< num_addrs
; i
++) {
1088 if(at
[i
].parse_addr
) {
1090 if((*at
[i
].parse_addr
)(context
, string
, &addr
) == 0) {
1091 ALLOC_SEQ(addresses
, 1);
1092 if (addresses
->val
== NULL
) {
1093 krb5_set_error_string(context
, "malloc: out of memory");
1096 addresses
->val
[0] = addr
;
1102 error
= getaddrinfo (string
, NULL
, NULL
, &ai
);
1105 krb5_set_error_string (context
, "%s: %s", string
, gai_strerror(error
));
1106 return krb5_eai_to_heim_errno(error
, save_errno
);
1110 for (a
= ai
; a
!= NULL
; a
= a
->ai_next
)
1113 ALLOC_SEQ(addresses
, n
);
1114 if (addresses
->val
== NULL
) {
1115 krb5_set_error_string(context
, "malloc: out of memory");
1121 for (a
= ai
, i
= 0; a
!= NULL
; a
= a
->ai_next
) {
1122 if (krb5_sockaddr2address (context
, ai
->ai_addr
, &addresses
->val
[i
]))
1124 if(krb5_address_search(context
, &addresses
->val
[i
], addresses
))
1134 * krb5_address_order compares the addresses addr1 and addr2 so that
1135 * it can be used for sorting addresses. If the addresses are the same
1136 * address krb5_address_order will return 0. Behavies like memcmp(2).
1138 * @param context a Keberos context
1139 * @param addr1 krb5_address to compare
1140 * @param addr2 krb5_address to compare
1142 * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and
1143 * addr2 is the same address, > 0 if addr2 is "less" then addr1.
1145 * @ingroup krb5_address
1148 int KRB5_LIB_FUNCTION
1149 krb5_address_order(krb5_context context
,
1150 const krb5_address
*addr1
,
1151 const krb5_address
*addr2
)
1153 /* this sucks; what if both addresses have order functions, which
1154 should we call? this works for now, though */
1155 struct addr_operations
*a
;
1156 a
= find_atype(addr1
->addr_type
);
1158 krb5_set_error_string (context
, "Address family %d not supported",
1160 return KRB5_PROG_ATYPE_NOSUPP
;
1162 if(a
->order_addr
!= NULL
)
1163 return (*a
->order_addr
)(context
, addr1
, addr2
);
1164 a
= find_atype(addr2
->addr_type
);
1166 krb5_set_error_string (context
, "Address family %d not supported",
1168 return KRB5_PROG_ATYPE_NOSUPP
;
1170 if(a
->order_addr
!= NULL
)
1171 return (*a
->order_addr
)(context
, addr1
, addr2
);
1173 if(addr1
->addr_type
!= addr2
->addr_type
)
1174 return addr1
->addr_type
- addr2
->addr_type
;
1175 if(addr1
->address
.length
!= addr2
->address
.length
)
1176 return addr1
->address
.length
- addr2
->address
.length
;
1177 return memcmp (addr1
->address
.data
,
1178 addr2
->address
.data
,
1179 addr1
->address
.length
);
1183 * krb5_address_compare compares the addresses addr1 and addr2.
1184 * Returns TRUE if the two addresses are the same.
1186 * @param context a Keberos context
1187 * @param addr1 address to compare
1188 * @param addr2 address to compare
1190 * @return Return an TRUE is the address are the same FALSE if not
1192 * @ingroup krb5_address
1195 krb5_boolean KRB5_LIB_FUNCTION
1196 krb5_address_compare(krb5_context context
,
1197 const krb5_address
*addr1
,
1198 const krb5_address
*addr2
)
1200 return krb5_address_order (context
, addr1
, addr2
) == 0;
1204 * krb5_address_search checks if the address addr is a member of the
1205 * address set list addrlist .
1207 * @param context a Keberos context.
1208 * @param addr address to search for.
1209 * @param addrlist list of addresses to look in for addr.
1211 * @return Return an error code or 0.
1213 * @ingroup krb5_address
1216 krb5_boolean KRB5_LIB_FUNCTION
1217 krb5_address_search(krb5_context context
,
1218 const krb5_address
*addr
,
1219 const krb5_addresses
*addrlist
)
1223 for (i
= 0; i
< addrlist
->len
; ++i
)
1224 if (krb5_address_compare (context
, addr
, &addrlist
->val
[i
]))
1230 * krb5_free_address frees the data stored in the address that is
1231 * alloced with any of the krb5_address functions.
1233 * @param context a Keberos context
1234 * @param address addresss to be freed.
1236 * @return Return an error code or 0.
1238 * @ingroup krb5_address
1241 krb5_error_code KRB5_LIB_FUNCTION
1242 krb5_free_address(krb5_context context
,
1243 krb5_address
*address
)
1245 struct addr_operations
*a
= find_atype (address
->addr_type
);
1246 if(a
!= NULL
&& a
->free_addr
!= NULL
)
1247 return (*a
->free_addr
)(context
, address
);
1248 krb5_data_free (&address
->address
);
1249 memset(address
, 0, sizeof(*address
));
1254 * krb5_free_addresses frees the data stored in the address that is
1255 * alloced with any of the krb5_address functions.
1257 * @param context a Keberos context
1258 * @param addresses addressses to be freed.
1260 * @return Return an error code or 0.
1262 * @ingroup krb5_address
1265 krb5_error_code KRB5_LIB_FUNCTION
1266 krb5_free_addresses(krb5_context context
,
1267 krb5_addresses
*addresses
)
1270 for(i
= 0; i
< addresses
->len
; i
++)
1271 krb5_free_address(context
, &addresses
->val
[i
]);
1272 free(addresses
->val
);
1274 addresses
->val
= NULL
;
1279 * krb5_copy_address copies the content of address
1280 * inaddr to outaddr.
1282 * @param context a Keberos context
1283 * @param inaddr pointer to source address
1284 * @param outaddr pointer to destination address
1286 * @return Return an error code or 0.
1288 * @ingroup krb5_address
1291 krb5_error_code KRB5_LIB_FUNCTION
1292 krb5_copy_address(krb5_context context
,
1293 const krb5_address
*inaddr
,
1294 krb5_address
*outaddr
)
1296 struct addr_operations
*a
= find_af (inaddr
->addr_type
);
1297 if(a
!= NULL
&& a
->copy_addr
!= NULL
)
1298 return (*a
->copy_addr
)(context
, inaddr
, outaddr
);
1299 return copy_HostAddress(inaddr
, outaddr
);
1303 * krb5_copy_addresses copies the content of addresses
1304 * inaddr to outaddr.
1306 * @param context a Keberos context
1307 * @param inaddr pointer to source addresses
1308 * @param outaddr pointer to destination addresses
1310 * @return Return an error code or 0.
1312 * @ingroup krb5_address
1315 krb5_error_code KRB5_LIB_FUNCTION
1316 krb5_copy_addresses(krb5_context context
,
1317 const krb5_addresses
*inaddr
,
1318 krb5_addresses
*outaddr
)
1321 ALLOC_SEQ(outaddr
, inaddr
->len
);
1322 if(inaddr
->len
> 0 && outaddr
->val
== NULL
)
1324 for(i
= 0; i
< inaddr
->len
; i
++)
1325 krb5_copy_address(context
, &inaddr
->val
[i
], &outaddr
->val
[i
]);
1330 * krb5_append_addresses adds the set of addresses in source to
1331 * dest. While copying the addresses, duplicates are also sorted out.
1333 * @param context a Keberos context
1334 * @param dest destination of copy operation
1335 * @param source adresses that are going to be added to dest
1337 * @return Return an error code or 0.
1339 * @ingroup krb5_address
1342 krb5_error_code KRB5_LIB_FUNCTION
1343 krb5_append_addresses(krb5_context context
,
1344 krb5_addresses
*dest
,
1345 const krb5_addresses
*source
)
1348 krb5_error_code ret
;
1350 if(source
->len
> 0) {
1351 tmp
= realloc(dest
->val
, (dest
->len
+ source
->len
) * sizeof(*tmp
));
1353 krb5_set_error_string(context
, "realloc: out of memory");
1357 for(i
= 0; i
< source
->len
; i
++) {
1358 /* skip duplicates */
1359 if(krb5_address_search(context
, &source
->val
[i
], dest
))
1361 ret
= krb5_copy_address(context
,
1363 &dest
->val
[dest
->len
]);
1373 * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
1375 * @param context a Keberos context
1376 * @param res built address from addr/port
1377 * @param addr address to use
1378 * @param port port to use
1380 * @return Return an error code or 0.
1382 * @ingroup krb5_address
1385 krb5_error_code KRB5_LIB_FUNCTION
1386 krb5_make_addrport (krb5_context context
,
1387 krb5_address
**res
, const krb5_address
*addr
, int16_t port
)
1389 krb5_error_code ret
;
1390 size_t len
= addr
->address
.length
+ 2 + 4 * 4;
1393 *res
= malloc (sizeof(**res
));
1395 krb5_set_error_string(context
, "malloc: out of memory");
1398 (*res
)->addr_type
= KRB5_ADDRESS_ADDRPORT
;
1399 ret
= krb5_data_alloc (&(*res
)->address
, len
);
1401 krb5_set_error_string(context
, "malloc: out of memory");
1406 p
= (*res
)->address
.data
;
1409 *p
++ = (addr
->addr_type
) & 0xFF;
1410 *p
++ = (addr
->addr_type
>> 8) & 0xFF;
1412 *p
++ = (addr
->address
.length
) & 0xFF;
1413 *p
++ = (addr
->address
.length
>> 8) & 0xFF;
1414 *p
++ = (addr
->address
.length
>> 16) & 0xFF;
1415 *p
++ = (addr
->address
.length
>> 24) & 0xFF;
1417 memcpy (p
, addr
->address
.data
, addr
->address
.length
);
1418 p
+= addr
->address
.length
;
1422 *p
++ = (KRB5_ADDRESS_IPPORT
) & 0xFF;
1423 *p
++ = (KRB5_ADDRESS_IPPORT
>> 8) & 0xFF;
1426 *p
++ = (2 >> 8) & 0xFF;
1427 *p
++ = (2 >> 16) & 0xFF;
1428 *p
++ = (2 >> 24) & 0xFF;
1430 memcpy (p
, &port
, 2);
1437 * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
1438 * them in `low' and `high'.
1440 * @param context a Keberos context
1441 * @param inaddr address in prefixlen that the bondery searched
1442 * @param prefixlen width of boundery
1443 * @param low lowest address
1444 * @param high highest address
1446 * @return Return an error code or 0.
1448 * @ingroup krb5_address
1451 krb5_error_code KRB5_LIB_FUNCTION
1452 krb5_address_prefixlen_boundary(krb5_context context
,
1453 const krb5_address
*inaddr
,
1454 unsigned long prefixlen
,
1458 struct addr_operations
*a
= find_atype (inaddr
->addr_type
);
1459 if(a
!= NULL
&& a
->mask_boundary
!= NULL
)
1460 return (*a
->mask_boundary
)(context
, inaddr
, prefixlen
, low
, high
);
1461 krb5_set_error_string(context
, "Address family %d doesn't support "
1462 "address mask operation", inaddr
->addr_type
);
1463 return KRB5_PROG_ATYPE_NOSUPP
;