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 struct addr_operations
{
38 krb5_address_type atype
;
39 size_t max_sockaddr_size
;
40 krb5_error_code (*sockaddr2addr
)(const struct sockaddr
*, krb5_address
*);
41 krb5_error_code (*sockaddr2port
)(const struct sockaddr
*, int16_t *);
42 void (*addr2sockaddr
)(const krb5_address
*, struct sockaddr
*,
43 krb5_socklen_t
*sa_size
, int port
);
44 void (*h_addr2sockaddr
)(const char *, struct sockaddr
*, krb5_socklen_t
*, int);
45 krb5_error_code (*h_addr2addr
)(const char *, krb5_address
*);
46 krb5_boolean (*uninteresting
)(const struct sockaddr
*);
47 krb5_boolean (*is_loopback
)(const struct sockaddr
*);
48 void (*anyaddr
)(struct sockaddr
*, krb5_socklen_t
*, int);
49 int (*print_addr
)(const krb5_address
*, char *, size_t);
50 int (*parse_addr
)(krb5_context
, const char*, krb5_address
*);
51 int (*order_addr
)(krb5_context
, const krb5_address
*, const krb5_address
*);
52 int (*free_addr
)(krb5_context
, krb5_address
*);
53 int (*copy_addr
)(krb5_context
, const krb5_address
*, krb5_address
*);
54 int (*mask_boundary
)(krb5_context
, const krb5_address
*, unsigned long,
55 krb5_address
*, krb5_address
*);
59 * AF_INET - aka IPv4 implementation
62 static krb5_error_code
63 ipv4_sockaddr2addr (const struct sockaddr
*sa
, krb5_address
*a
)
65 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
68 a
->addr_type
= KRB5_ADDRESS_INET
;
69 memcpy (buf
, &sin4
->sin_addr
, 4);
70 return krb5_data_copy(&a
->address
, buf
, 4);
73 static krb5_error_code
74 ipv4_sockaddr2port (const struct sockaddr
*sa
, int16_t *port
)
76 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
78 *port
= sin4
->sin_port
;
83 ipv4_addr2sockaddr (const krb5_address
*a
,
85 krb5_socklen_t
*sa_size
,
88 struct sockaddr_in tmp
;
90 memset (&tmp
, 0, sizeof(tmp
));
91 tmp
.sin_family
= AF_INET
;
92 memcpy (&tmp
.sin_addr
, a
->address
.data
, 4);
94 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
95 *sa_size
= sizeof(tmp
);
99 ipv4_h_addr2sockaddr(const char *addr
,
101 krb5_socklen_t
*sa_size
,
104 struct sockaddr_in tmp
;
106 memset (&tmp
, 0, sizeof(tmp
));
107 tmp
.sin_family
= AF_INET
;
109 tmp
.sin_addr
= *((const struct in_addr
*)addr
);
110 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
111 *sa_size
= sizeof(tmp
);
114 static krb5_error_code
115 ipv4_h_addr2addr (const char *addr
,
118 unsigned char buf
[4];
120 a
->addr_type
= KRB5_ADDRESS_INET
;
121 memcpy(buf
, addr
, 4);
122 return krb5_data_copy(&a
->address
, buf
, 4);
126 * Are there any addresses that should be considered `uninteresting'?
130 ipv4_uninteresting (const struct sockaddr
*sa
)
132 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
134 if (sin4
->sin_addr
.s_addr
== INADDR_ANY
)
141 ipv4_is_loopback (const struct sockaddr
*sa
)
143 const struct sockaddr_in
*sin4
= (const struct sockaddr_in
*)sa
;
145 if ((ntohl(sin4
->sin_addr
.s_addr
) >> 24) == IN_LOOPBACKNET
)
152 ipv4_anyaddr (struct sockaddr
*sa
, krb5_socklen_t
*sa_size
, int port
)
154 struct sockaddr_in tmp
;
156 memset (&tmp
, 0, sizeof(tmp
));
157 tmp
.sin_family
= AF_INET
;
159 tmp
.sin_addr
.s_addr
= INADDR_ANY
;
160 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
161 *sa_size
= sizeof(tmp
);
165 ipv4_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
169 memcpy (&ia
, addr
->address
.data
, 4);
171 return snprintf (str
, len
, "IPv4:%s", inet_ntoa(ia
));
175 ipv4_parse_addr (krb5_context context
, const char *address
, krb5_address
*addr
)
180 p
= strchr(address
, ':');
183 if(strncasecmp(address
, "ip:", p
- address
) != 0 &&
184 strncasecmp(address
, "ip4:", p
- address
) != 0 &&
185 strncasecmp(address
, "ipv4:", p
- address
) != 0 &&
186 strncasecmp(address
, "inet:", p
- address
) != 0)
190 if(inet_aton(p
, &a
) == 0)
192 addr
->addr_type
= KRB5_ADDRESS_INET
;
193 if(krb5_data_alloc(&addr
->address
, 4) != 0)
195 _krb5_put_int(addr
->address
.data
, ntohl(a
.s_addr
), addr
->address
.length
);
200 ipv4_mask_boundary(krb5_context context
, const krb5_address
*inaddr
,
201 unsigned long len
, krb5_address
*low
, krb5_address
*high
)
204 uint32_t l
, h
, m
= 0xffffffff;
207 krb5_set_error_message(context
, KRB5_PROG_ATYPE_NOSUPP
,
208 N_("IPv4 prefix too large (%ld)", "len"), len
);
209 return KRB5_PROG_ATYPE_NOSUPP
;
213 _krb5_get_int(inaddr
->address
.data
, &ia
, inaddr
->address
.length
);
218 low
->addr_type
= KRB5_ADDRESS_INET
;
219 if(krb5_data_alloc(&low
->address
, 4) != 0)
221 _krb5_put_int(low
->address
.data
, l
, low
->address
.length
);
223 high
->addr_type
= KRB5_ADDRESS_INET
;
224 if(krb5_data_alloc(&high
->address
, 4) != 0) {
225 krb5_free_address(context
, low
);
228 _krb5_put_int(high
->address
.data
, h
, high
->address
.length
);
235 * AF_INET6 - aka IPv6 implementation
240 static krb5_error_code
241 ipv6_sockaddr2addr (const struct sockaddr
*sa
, krb5_address
*a
)
243 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
245 if (IN6_IS_ADDR_V4MAPPED(&sin6
->sin6_addr
)) {
246 unsigned char buf
[4];
248 a
->addr_type
= KRB5_ADDRESS_INET
;
249 #ifndef IN6_ADDR_V6_TO_V4
250 #ifdef IN6_EXTRACT_V4ADDR
251 #define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
253 #define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
256 memcpy (buf
, IN6_ADDR_V6_TO_V4(&sin6
->sin6_addr
), 4);
257 return krb5_data_copy(&a
->address
, buf
, 4);
259 a
->addr_type
= KRB5_ADDRESS_INET6
;
260 return krb5_data_copy(&a
->address
,
262 sizeof(sin6
->sin6_addr
));
266 static krb5_error_code
267 ipv6_sockaddr2port (const struct sockaddr
*sa
, int16_t *port
)
269 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
271 *port
= sin6
->sin6_port
;
276 ipv6_addr2sockaddr (const krb5_address
*a
,
278 krb5_socklen_t
*sa_size
,
281 struct sockaddr_in6 tmp
;
283 memset (&tmp
, 0, sizeof(tmp
));
284 tmp
.sin6_family
= AF_INET6
;
285 memcpy (&tmp
.sin6_addr
, a
->address
.data
, sizeof(tmp
.sin6_addr
));
286 tmp
.sin6_port
= port
;
287 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
288 *sa_size
= sizeof(tmp
);
292 ipv6_h_addr2sockaddr(const char *addr
,
294 krb5_socklen_t
*sa_size
,
297 struct sockaddr_in6 tmp
;
299 memset (&tmp
, 0, sizeof(tmp
));
300 tmp
.sin6_family
= AF_INET6
;
301 tmp
.sin6_port
= port
;
302 tmp
.sin6_addr
= *((const struct in6_addr
*)addr
);
303 memcpy(sa
, &tmp
, min(sizeof(tmp
), *sa_size
));
304 *sa_size
= sizeof(tmp
);
307 static krb5_error_code
308 ipv6_h_addr2addr (const char *addr
,
311 a
->addr_type
= KRB5_ADDRESS_INET6
;
312 return krb5_data_copy(&a
->address
, addr
, sizeof(struct in6_addr
));
320 ipv6_uninteresting (const struct sockaddr
*sa
)
322 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
323 const struct in6_addr
*in6
= (const struct in6_addr
*)&sin6
->sin6_addr
;
325 return IN6_IS_ADDR_LINKLOCAL(in6
)
326 || IN6_IS_ADDR_V4COMPAT(in6
);
330 ipv6_is_loopback (const struct sockaddr
*sa
)
332 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
333 const struct in6_addr
*in6
= (const struct in6_addr
*)&sin6
->sin6_addr
;
335 return (IN6_IS_ADDR_LOOPBACK(in6
));
339 ipv6_anyaddr (struct sockaddr
*sa
, krb5_socklen_t
*sa_size
, int port
)
341 struct sockaddr_in6 tmp
;
343 memset (&tmp
, 0, sizeof(tmp
));
344 tmp
.sin6_family
= AF_INET6
;
345 tmp
.sin6_port
= port
;
346 tmp
.sin6_addr
= in6addr_any
;
347 *sa_size
= sizeof(tmp
);
351 ipv6_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
353 char buf
[128], buf2
[3];
354 if(inet_ntop(AF_INET6
, addr
->address
.data
, buf
, sizeof(buf
)) == NULL
)
356 /* XXX this is pretty ugly, but better than abort() */
358 unsigned char *p
= addr
->address
.data
;
360 for(i
= 0; i
< addr
->address
.length
; i
++) {
361 snprintf(buf2
, sizeof(buf2
), "%02x", p
[i
]);
362 if(i
> 0 && (i
& 1) == 0)
363 strlcat(buf
, ":", sizeof(buf
));
364 strlcat(buf
, buf2
, sizeof(buf
));
367 return snprintf(str
, len
, "IPv6:%s", buf
);
371 ipv6_parse_addr (krb5_context context
, const char *address
, krb5_address
*addr
)
377 p
= strchr(address
, ':');
380 if(strncasecmp(address
, "ip6:", p
- address
) == 0 ||
381 strncasecmp(address
, "ipv6:", p
- address
) == 0 ||
382 strncasecmp(address
, "inet6:", p
- address
) == 0)
386 ret
= inet_pton(AF_INET6
, address
, &in6
.s6_addr
);
388 addr
->addr_type
= KRB5_ADDRESS_INET6
;
389 ret
= krb5_data_alloc(&addr
->address
, sizeof(in6
.s6_addr
));
392 memcpy(addr
->address
.data
, in6
.s6_addr
, sizeof(in6
.s6_addr
));
399 ipv6_mask_boundary(krb5_context context
, const krb5_address
*inaddr
,
400 unsigned long len
, krb5_address
*low
, krb5_address
*high
)
402 struct in6_addr addr
, laddr
, haddr
;
407 krb5_set_error_message(context
, KRB5_PROG_ATYPE_NOSUPP
,
408 N_("IPv6 prefix too large (%ld)", "length"), len
);
409 return KRB5_PROG_ATYPE_NOSUPP
;
412 if (inaddr
->address
.length
!= sizeof(addr
)) {
413 krb5_set_error_message(context
, KRB5_PROG_ATYPE_NOSUPP
,
414 N_("IPv6 addr bad length", ""));
415 return KRB5_PROG_ATYPE_NOSUPP
;
418 memcpy(&addr
, inaddr
->address
.data
, inaddr
->address
.length
);
420 for (i
= 0; i
< 16; i
++) {
421 sub_len
= min(8, len
);
423 m
= 0xff << (8 - sub_len
);
425 laddr
.s6_addr
[i
] = addr
.s6_addr
[i
] & m
;
426 haddr
.s6_addr
[i
] = (addr
.s6_addr
[i
] & m
) | ~m
;
434 low
->addr_type
= KRB5_ADDRESS_INET6
;
435 if (krb5_data_alloc(&low
->address
, sizeof(laddr
.s6_addr
)) != 0)
437 memcpy(low
->address
.data
, laddr
.s6_addr
, sizeof(laddr
.s6_addr
));
439 high
->addr_type
= KRB5_ADDRESS_INET6
;
440 if (krb5_data_alloc(&high
->address
, sizeof(haddr
.s6_addr
)) != 0) {
441 krb5_free_address(context
, low
);
444 memcpy(high
->address
.data
, haddr
.s6_addr
, sizeof(haddr
.s6_addr
));
451 #ifndef HEIMDAL_SMALLER
457 #define KRB5_ADDRESS_ARANGE (-100)
465 arange_parse_addr (krb5_context context
,
466 const char *address
, krb5_address
*addr
)
469 krb5_address low0
, high0
;
473 if(strncasecmp(address
, "RANGE:", 6) != 0)
478 p
= strrchr(address
, '/');
480 krb5_addresses addrmask
;
484 if (strlcpy(buf
, address
, sizeof(buf
)) > sizeof(buf
))
486 buf
[p
- address
] = '\0';
487 ret
= krb5_parse_address(context
, buf
, &addrmask
);
490 if(addrmask
.len
!= 1) {
491 krb5_free_addresses(context
, &addrmask
);
495 address
+= p
- address
+ 1;
497 num
= strtol(address
, &q
, 10);
498 if (q
== address
|| *q
!= '\0' || num
< 0) {
499 krb5_free_addresses(context
, &addrmask
);
503 ret
= krb5_address_prefixlen_boundary(context
, &addrmask
.val
[0], num
,
505 krb5_free_addresses(context
, &addrmask
);
510 krb5_addresses low
, high
;
512 strsep_copy(&address
, "-", buf
, sizeof(buf
));
513 ret
= krb5_parse_address(context
, buf
, &low
);
517 krb5_free_addresses(context
, &low
);
521 strsep_copy(&address
, "-", buf
, sizeof(buf
));
522 ret
= krb5_parse_address(context
, buf
, &high
);
524 krb5_free_addresses(context
, &low
);
528 if(high
.len
!= 1 && high
.val
[0].addr_type
!= low
.val
[0].addr_type
) {
529 krb5_free_addresses(context
, &low
);
530 krb5_free_addresses(context
, &high
);
534 ret
= krb5_copy_address(context
, &high
.val
[0], &high0
);
536 ret
= krb5_copy_address(context
, &low
.val
[0], &low0
);
538 krb5_free_address(context
, &high0
);
540 krb5_free_addresses(context
, &low
);
541 krb5_free_addresses(context
, &high
);
546 krb5_data_alloc(&addr
->address
, sizeof(*a
));
547 addr
->addr_type
= KRB5_ADDRESS_ARANGE
;
548 a
= addr
->address
.data
;
550 if(krb5_address_order(context
, &low0
, &high0
) < 0) {
561 arange_free (krb5_context context
, krb5_address
*addr
)
564 a
= addr
->address
.data
;
565 krb5_free_address(context
, &a
->low
);
566 krb5_free_address(context
, &a
->high
);
567 krb5_data_free(&addr
->address
);
573 arange_copy (krb5_context context
, const krb5_address
*inaddr
,
574 krb5_address
*outaddr
)
577 struct arange
*i
, *o
;
579 outaddr
->addr_type
= KRB5_ADDRESS_ARANGE
;
580 ret
= krb5_data_alloc(&outaddr
->address
, sizeof(*o
));
583 i
= inaddr
->address
.data
;
584 o
= outaddr
->address
.data
;
585 ret
= krb5_copy_address(context
, &i
->low
, &o
->low
);
587 krb5_data_free(&outaddr
->address
);
590 ret
= krb5_copy_address(context
, &i
->high
, &o
->high
);
592 krb5_free_address(context
, &o
->low
);
593 krb5_data_free(&outaddr
->address
);
600 arange_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
604 size_t l
, size
, ret_len
;
606 a
= addr
->address
.data
;
608 l
= strlcpy(str
, "RANGE:", len
);
614 ret
= krb5_print_address (&a
->low
, str
+ size
, len
- size
, &l
);
623 l
= strlcat(str
+ size
, "-", len
- size
);
630 ret
= krb5_print_address (&a
->high
, str
+ size
, len
- size
, &l
);
639 arange_order_addr(krb5_context context
,
640 const krb5_address
*addr1
,
641 const krb5_address
*addr2
)
643 int tmp1
, tmp2
, sign
;
645 const krb5_address
*a2
;
647 if(addr1
->addr_type
== KRB5_ADDRESS_ARANGE
) {
648 a
= addr1
->address
.data
;
651 } else if(addr2
->addr_type
== KRB5_ADDRESS_ARANGE
) {
652 a
= addr2
->address
.data
;
657 UNREACHABLE(return 0);
660 if(a2
->addr_type
== KRB5_ADDRESS_ARANGE
) {
661 struct arange
*b
= a2
->address
.data
;
662 tmp1
= krb5_address_order(context
, &a
->low
, &b
->low
);
665 return sign
* krb5_address_order(context
, &a
->high
, &b
->high
);
666 } else if(a2
->addr_type
== a
->low
.addr_type
) {
667 tmp1
= krb5_address_order(context
, &a
->low
, a2
);
670 tmp2
= krb5_address_order(context
, &a
->high
, a2
);
675 return sign
* (addr1
->addr_type
- addr2
->addr_type
);
679 #endif /* HEIMDAL_SMALLER */
682 addrport_print_addr (const krb5_address
*addr
, char *str
, size_t len
)
685 krb5_address addr1
, addr2
;
687 size_t ret_len
= 0, l
, size
= 0;
690 sp
= krb5_storage_from_data((krb5_data
*)rk_UNCONST(&addr
->address
));
694 /* for totally obscure reasons, these are not in network byteorder */
695 krb5_storage_set_byteorder(sp
, KRB5_STORAGE_BYTEORDER_LE
);
697 krb5_storage_seek(sp
, 2, SEEK_CUR
); /* skip first two bytes */
698 krb5_ret_address(sp
, &addr1
);
700 krb5_storage_seek(sp
, 2, SEEK_CUR
); /* skip two bytes */
701 krb5_ret_address(sp
, &addr2
);
702 krb5_storage_free(sp
);
703 if(addr2
.addr_type
== KRB5_ADDRESS_IPPORT
&& addr2
.address
.length
== 2) {
705 _krb5_get_int(addr2
.address
.data
, &value
, 2);
708 l
= strlcpy(str
, "ADDRPORT:", len
);
715 ret
= krb5_print_address(&addr1
, str
+ size
, len
- size
, &l
);
724 ret
= snprintf(str
+ size
, len
- size
, ",PORT=%u", port
);
731 static struct addr_operations at
[] = {
733 AF_INET
, KRB5_ADDRESS_INET
, sizeof(struct sockaddr_in
),
737 ipv4_h_addr2sockaddr
,
751 AF_INET6
, KRB5_ADDRESS_INET6
, sizeof(struct sockaddr_in6
),
755 ipv6_h_addr2sockaddr
,
768 #ifndef HEIMDAL_SMALLER
769 /* fake address type */
771 KRB5_ADDRESS_ARANGE
, KRB5_ADDRESS_ARANGE
, sizeof(struct arange
),
789 KRB5_ADDRESS_ADDRPORT
, KRB5_ADDRESS_ADDRPORT
, 0,
806 static int num_addrs
= sizeof(at
) / sizeof(at
[0]);
808 static size_t max_sockaddr_size
= 0;
814 static struct addr_operations
*
817 struct addr_operations
*a
;
819 for (a
= at
; a
< at
+ num_addrs
; ++a
)
825 static struct addr_operations
*
826 find_atype(krb5_address_type atype
)
828 struct addr_operations
*a
;
830 for (a
= at
; a
< at
+ num_addrs
; ++a
)
831 if (atype
== a
->atype
)
837 * krb5_sockaddr2address stores a address a "struct sockaddr" sa in
838 * the krb5_address addr.
840 * @param context a Keberos context
841 * @param sa a struct sockaddr to extract the address from
842 * @param addr an Kerberos 5 address to store the address in.
844 * @return Return an error code or 0.
846 * @ingroup krb5_address
849 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
850 krb5_sockaddr2address (krb5_context context
,
851 const struct sockaddr
*sa
, krb5_address
*addr
)
853 struct addr_operations
*a
= find_af(sa
->sa_family
);
855 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
856 N_("Address family %d not supported", ""),
858 return KRB5_PROG_ATYPE_NOSUPP
;
860 return (*a
->sockaddr2addr
)(sa
, addr
);
864 * krb5_sockaddr2port extracts a port (if possible) from a "struct
867 * @param context a Keberos context
868 * @param sa a struct sockaddr to extract the port from
869 * @param port a pointer to an int16_t store the port in.
871 * @return Return an error code or 0. Will return
872 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
874 * @ingroup krb5_address
877 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
878 krb5_sockaddr2port (krb5_context context
,
879 const struct sockaddr
*sa
, int16_t *port
)
881 struct addr_operations
*a
= find_af(sa
->sa_family
);
883 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
884 N_("Address family %d not supported", ""),
886 return KRB5_PROG_ATYPE_NOSUPP
;
888 return (*a
->sockaddr2port
)(sa
, port
);
892 * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr
893 * and port. The argument sa_size should initially contain the size of
894 * the sa and after the call, it will contain the actual length of the
895 * address. In case of the sa is too small to fit the whole address,
896 * the up to *sa_size will be stored, and then *sa_size will be set to
897 * the required length.
899 * @param context a Keberos context
900 * @param addr the address to copy the from
901 * @param sa the struct sockaddr that will be filled in
902 * @param sa_size pointer to length of sa, and after the call, it will
903 * contain the actual length of the address.
904 * @param port set port in sa.
906 * @return Return an error code or 0. Will return
907 * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
909 * @ingroup krb5_address
912 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
913 krb5_addr2sockaddr (krb5_context context
,
914 const krb5_address
*addr
,
916 krb5_socklen_t
*sa_size
,
919 struct addr_operations
*a
= find_atype(addr
->addr_type
);
922 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
923 N_("Address type %d not supported",
924 "krb5_address type"),
926 return KRB5_PROG_ATYPE_NOSUPP
;
928 if (a
->addr2sockaddr
== NULL
) {
929 krb5_set_error_message (context
,
930 KRB5_PROG_ATYPE_NOSUPP
,
931 N_("Can't convert address type %d to sockaddr", ""),
933 return KRB5_PROG_ATYPE_NOSUPP
;
935 (*a
->addr2sockaddr
)(addr
, sa
, sa_size
, port
);
940 * krb5_max_sockaddr_size returns the max size of the .Li struct
941 * sockaddr that the Kerberos library will return.
943 * @return Return an size_t of the maximum struct sockaddr.
945 * @ingroup krb5_address
948 KRB5_LIB_FUNCTION
size_t KRB5_LIB_CALL
949 krb5_max_sockaddr_size (void)
951 if (max_sockaddr_size
== 0) {
952 struct addr_operations
*a
;
954 for(a
= at
; a
< at
+ num_addrs
; ++a
)
955 max_sockaddr_size
= max(max_sockaddr_size
, a
->max_sockaddr_size
);
957 return max_sockaddr_size
;
961 * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the
962 * kerberos library thinks are uninteresting. One example are link
965 * @param sa pointer to struct sockaddr that might be interesting.
967 * @return Return a non zero for uninteresting addresses.
969 * @ingroup krb5_address
972 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
973 krb5_sockaddr_uninteresting(const struct sockaddr
*sa
)
975 struct addr_operations
*a
= find_af(sa
->sa_family
);
976 if (a
== NULL
|| a
->uninteresting
== NULL
)
978 return (*a
->uninteresting
)(sa
);
981 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
982 krb5_sockaddr_is_loopback(const struct sockaddr
*sa
)
984 struct addr_operations
*a
= find_af(sa
->sa_family
);
985 if (a
== NULL
|| a
->is_loopback
== NULL
)
987 return (*a
->is_loopback
)(sa
);
991 * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and
992 * the "struct hostent" (see gethostbyname(3) ) h_addr_list
993 * component. The argument sa_size should initially contain the size
994 * of the sa, and after the call, it will contain the actual length of
997 * @param context a Keberos context
998 * @param af addresses
999 * @param addr address
1000 * @param sa returned struct sockaddr
1001 * @param sa_size size of sa
1002 * @param port port to set in sa.
1004 * @return Return an error code or 0.
1006 * @ingroup krb5_address
1009 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1010 krb5_h_addr2sockaddr (krb5_context context
,
1012 const char *addr
, struct sockaddr
*sa
,
1013 krb5_socklen_t
*sa_size
,
1016 struct addr_operations
*a
= find_af(af
);
1018 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
1019 "Address family %d not supported", af
);
1020 return KRB5_PROG_ATYPE_NOSUPP
;
1022 (*a
->h_addr2sockaddr
)(addr
, sa
, sa_size
, port
);
1027 * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception
1028 * that it operates on a krb5_address instead of a struct sockaddr.
1030 * @param context a Keberos context
1031 * @param af address family
1032 * @param haddr host address from struct hostent.
1033 * @param addr returned krb5_address.
1035 * @return Return an error code or 0.
1037 * @ingroup krb5_address
1040 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1041 krb5_h_addr2addr (krb5_context context
,
1043 const char *haddr
, krb5_address
*addr
)
1045 struct addr_operations
*a
= find_af(af
);
1047 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
1048 N_("Address family %d not supported", ""), af
);
1049 return KRB5_PROG_ATYPE_NOSUPP
;
1051 return (*a
->h_addr2addr
)(haddr
, addr
);
1055 * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to
1056 * bind(2) to. The argument sa_size should initially contain the size
1057 * of the sa, and after the call, it will contain the actual length
1060 * @param context a Keberos context
1061 * @param af address family
1062 * @param sa sockaddr
1063 * @param sa_size lenght of sa.
1064 * @param port for to fill into sa.
1066 * @return Return an error code or 0.
1068 * @ingroup krb5_address
1071 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1072 krb5_anyaddr (krb5_context context
,
1074 struct sockaddr
*sa
,
1075 krb5_socklen_t
*sa_size
,
1078 struct addr_operations
*a
= find_af (af
);
1081 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
1082 N_("Address family %d not supported", ""), af
);
1083 return KRB5_PROG_ATYPE_NOSUPP
;
1086 (*a
->anyaddr
)(sa
, sa_size
, port
);
1091 * krb5_print_address prints the address in addr to the string string
1092 * that have the length len. If ret_len is not NULL, it will be filled
1093 * with the length of the string if size were unlimited (not including
1096 * @param addr address to be printed
1097 * @param str pointer string to print the address into
1098 * @param len length that will fit into area pointed to by "str".
1099 * @param ret_len return length the str.
1101 * @return Return an error code or 0.
1103 * @ingroup krb5_address
1106 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1107 krb5_print_address (const krb5_address
*addr
,
1108 char *str
, size_t len
, size_t *ret_len
)
1110 struct addr_operations
*a
= find_atype(addr
->addr_type
);
1113 if (a
== NULL
|| a
->print_addr
== NULL
) {
1119 l
= snprintf(s
, len
, "TYPE_%d:", addr
->addr_type
);
1120 if (l
< 0 || (size_t)l
>= len
)
1124 for(i
= 0; i
< addr
->address
.length
; i
++) {
1125 l
= snprintf(s
, len
, "%02x", ((char*)addr
->address
.data
)[i
]);
1126 if (l
< 0 || (size_t)l
>= len
)
1135 ret
= (*a
->print_addr
)(addr
, str
, len
);
1144 * krb5_parse_address returns the resolved hostname in string to the
1145 * krb5_addresses addresses .
1147 * @param context a Keberos context
1151 * @return Return an error code or 0.
1153 * @ingroup krb5_address
1156 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1157 krb5_parse_address(krb5_context context
,
1159 krb5_addresses
*addresses
)
1162 struct addrinfo
*ai
, *a
;
1167 addresses
->val
= NULL
;
1169 for(i
= 0; i
< num_addrs
; i
++) {
1170 if(at
[i
].parse_addr
) {
1172 if((*at
[i
].parse_addr
)(context
, string
, &addr
) == 0) {
1173 ALLOC_SEQ(addresses
, 1);
1174 if (addresses
->val
== NULL
) {
1175 krb5_set_error_message(context
, ENOMEM
,
1176 N_("malloc: out of memory", ""));
1179 addresses
->val
[0] = addr
;
1185 error
= getaddrinfo (string
, NULL
, NULL
, &ai
);
1187 krb5_error_code ret2
;
1189 ret2
= krb5_eai_to_heim_errno(error
, save_errno
);
1190 krb5_set_error_message (context
, ret2
, "%s: %s",
1191 string
, gai_strerror(error
));
1196 for (a
= ai
; a
!= NULL
; a
= a
->ai_next
)
1199 ALLOC_SEQ(addresses
, n
);
1200 if (addresses
->val
== NULL
) {
1201 krb5_set_error_message(context
, ENOMEM
,
1202 N_("malloc: out of memory", ""));
1208 for (a
= ai
, i
= 0; a
!= NULL
; a
= a
->ai_next
) {
1209 if (krb5_sockaddr2address (context
, ai
->ai_addr
, &addresses
->val
[i
]))
1211 if(krb5_address_search(context
, &addresses
->val
[i
], addresses
)) {
1212 krb5_free_address(context
, &addresses
->val
[i
]);
1223 * krb5_address_order compares the addresses addr1 and addr2 so that
1224 * it can be used for sorting addresses. If the addresses are the same
1225 * address krb5_address_order will return 0. Behavies like memcmp(2).
1227 * @param context a Keberos context
1228 * @param addr1 krb5_address to compare
1229 * @param addr2 krb5_address to compare
1231 * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and
1232 * addr2 is the same address, > 0 if addr2 is "less" then addr1.
1234 * @ingroup krb5_address
1237 KRB5_LIB_FUNCTION
int KRB5_LIB_CALL
1238 krb5_address_order(krb5_context context
,
1239 const krb5_address
*addr1
,
1240 const krb5_address
*addr2
)
1242 /* this sucks; what if both addresses have order functions, which
1243 should we call? this works for now, though */
1244 struct addr_operations
*a
;
1245 a
= find_atype(addr1
->addr_type
);
1247 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
1248 N_("Address family %d not supported", ""),
1250 return KRB5_PROG_ATYPE_NOSUPP
;
1252 if(a
->order_addr
!= NULL
)
1253 return (*a
->order_addr
)(context
, addr1
, addr2
);
1254 a
= find_atype(addr2
->addr_type
);
1256 krb5_set_error_message (context
, KRB5_PROG_ATYPE_NOSUPP
,
1257 N_("Address family %d not supported", ""),
1259 return KRB5_PROG_ATYPE_NOSUPP
;
1261 if(a
->order_addr
!= NULL
)
1262 return (*a
->order_addr
)(context
, addr1
, addr2
);
1264 if(addr1
->addr_type
!= addr2
->addr_type
)
1265 return addr1
->addr_type
- addr2
->addr_type
;
1266 if(addr1
->address
.length
!= addr2
->address
.length
)
1267 return addr1
->address
.length
- addr2
->address
.length
;
1268 return memcmp (addr1
->address
.data
,
1269 addr2
->address
.data
,
1270 addr1
->address
.length
);
1274 * krb5_address_compare compares the addresses addr1 and addr2.
1275 * Returns TRUE if the two addresses are the same.
1277 * @param context a Keberos context
1278 * @param addr1 address to compare
1279 * @param addr2 address to compare
1281 * @return Return an TRUE is the address are the same FALSE if not
1283 * @ingroup krb5_address
1286 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1287 krb5_address_compare(krb5_context context
,
1288 const krb5_address
*addr1
,
1289 const krb5_address
*addr2
)
1291 return krb5_address_order (context
, addr1
, addr2
) == 0;
1295 * krb5_address_search checks if the address addr is a member of the
1296 * address set list addrlist .
1298 * @param context a Keberos context.
1299 * @param addr address to search for.
1300 * @param addrlist list of addresses to look in for addr.
1302 * @return Return an error code or 0.
1304 * @ingroup krb5_address
1307 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
1308 krb5_address_search(krb5_context context
,
1309 const krb5_address
*addr
,
1310 const krb5_addresses
*addrlist
)
1314 for (i
= 0; i
< addrlist
->len
; ++i
)
1315 if (krb5_address_compare (context
, addr
, &addrlist
->val
[i
]))
1321 * krb5_free_address frees the data stored in the address that is
1322 * alloced with any of the krb5_address functions.
1324 * @param context a Keberos context
1325 * @param address addresss to be freed.
1327 * @return Return an error code or 0.
1329 * @ingroup krb5_address
1332 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1333 krb5_free_address(krb5_context context
,
1334 krb5_address
*address
)
1336 struct addr_operations
*a
= find_atype (address
->addr_type
);
1337 if(a
!= NULL
&& a
->free_addr
!= NULL
)
1338 return (*a
->free_addr
)(context
, address
);
1339 krb5_data_free (&address
->address
);
1340 memset(address
, 0, sizeof(*address
));
1345 * krb5_free_addresses frees the data stored in the address that is
1346 * alloced with any of the krb5_address functions.
1348 * @param context a Keberos context
1349 * @param addresses addressses to be freed.
1351 * @return Return an error code or 0.
1353 * @ingroup krb5_address
1356 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1357 krb5_free_addresses(krb5_context context
,
1358 krb5_addresses
*addresses
)
1361 for(i
= 0; i
< addresses
->len
; i
++)
1362 krb5_free_address(context
, &addresses
->val
[i
]);
1363 free(addresses
->val
);
1365 addresses
->val
= NULL
;
1370 * krb5_copy_address copies the content of address
1371 * inaddr to outaddr.
1373 * @param context a Keberos context
1374 * @param inaddr pointer to source address
1375 * @param outaddr pointer to destination address
1377 * @return Return an error code or 0.
1379 * @ingroup krb5_address
1382 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1383 krb5_copy_address(krb5_context context
,
1384 const krb5_address
*inaddr
,
1385 krb5_address
*outaddr
)
1387 struct addr_operations
*a
= find_af (inaddr
->addr_type
);
1388 if(a
!= NULL
&& a
->copy_addr
!= NULL
)
1389 return (*a
->copy_addr
)(context
, inaddr
, outaddr
);
1390 return copy_HostAddress(inaddr
, outaddr
);
1394 * krb5_copy_addresses copies the content of addresses
1395 * inaddr to outaddr.
1397 * @param context a Keberos context
1398 * @param inaddr pointer to source addresses
1399 * @param outaddr pointer to destination addresses
1401 * @return Return an error code or 0.
1403 * @ingroup krb5_address
1406 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1407 krb5_copy_addresses(krb5_context context
,
1408 const krb5_addresses
*inaddr
,
1409 krb5_addresses
*outaddr
)
1412 ALLOC_SEQ(outaddr
, inaddr
->len
);
1413 if(inaddr
->len
> 0 && outaddr
->val
== NULL
)
1415 for(i
= 0; i
< inaddr
->len
; i
++)
1416 krb5_copy_address(context
, &inaddr
->val
[i
], &outaddr
->val
[i
]);
1421 * krb5_append_addresses adds the set of addresses in source to
1422 * dest. While copying the addresses, duplicates are also sorted out.
1424 * @param context a Keberos context
1425 * @param dest destination of copy operation
1426 * @param source adresses that are going to be added to dest
1428 * @return Return an error code or 0.
1430 * @ingroup krb5_address
1433 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1434 krb5_append_addresses(krb5_context context
,
1435 krb5_addresses
*dest
,
1436 const krb5_addresses
*source
)
1439 krb5_error_code ret
;
1441 if(source
->len
> 0) {
1442 tmp
= realloc(dest
->val
, (dest
->len
+ source
->len
) * sizeof(*tmp
));
1444 krb5_set_error_message (context
, ENOMEM
,
1445 N_("malloc: out of memory", ""));
1449 for(i
= 0; i
< source
->len
; i
++) {
1450 /* skip duplicates */
1451 if(krb5_address_search(context
, &source
->val
[i
], dest
))
1453 ret
= krb5_copy_address(context
,
1455 &dest
->val
[dest
->len
]);
1465 * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
1467 * @param context a Keberos context
1468 * @param res built address from addr/port
1469 * @param addr address to use
1470 * @param port port to use
1472 * @return Return an error code or 0.
1474 * @ingroup krb5_address
1477 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1478 krb5_make_addrport (krb5_context context
,
1479 krb5_address
**res
, const krb5_address
*addr
, int16_t port
)
1481 krb5_error_code ret
;
1482 size_t len
= addr
->address
.length
+ 2 + 4 * 4;
1485 *res
= malloc (sizeof(**res
));
1487 krb5_set_error_message (context
, ENOMEM
,
1488 N_("malloc: out of memory", ""));
1491 (*res
)->addr_type
= KRB5_ADDRESS_ADDRPORT
;
1492 ret
= krb5_data_alloc (&(*res
)->address
, len
);
1494 krb5_set_error_message (context
, ret
,
1495 N_("malloc: out of memory", ""));
1500 p
= (*res
)->address
.data
;
1503 *p
++ = (addr
->addr_type
) & 0xFF;
1504 *p
++ = (addr
->addr_type
>> 8) & 0xFF;
1506 *p
++ = (addr
->address
.length
) & 0xFF;
1507 *p
++ = (addr
->address
.length
>> 8) & 0xFF;
1508 *p
++ = (addr
->address
.length
>> 16) & 0xFF;
1509 *p
++ = (addr
->address
.length
>> 24) & 0xFF;
1511 memcpy (p
, addr
->address
.data
, addr
->address
.length
);
1512 p
+= addr
->address
.length
;
1516 *p
++ = (KRB5_ADDRESS_IPPORT
) & 0xFF;
1517 *p
++ = (KRB5_ADDRESS_IPPORT
>> 8) & 0xFF;
1520 *p
++ = (2 >> 8) & 0xFF;
1521 *p
++ = (2 >> 16) & 0xFF;
1522 *p
++ = (2 >> 24) & 0xFF;
1524 memcpy (p
, &port
, 2);
1530 * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
1531 * them in `low' and `high'.
1533 * @param context a Keberos context
1534 * @param inaddr address in prefixlen that the bondery searched
1535 * @param prefixlen width of boundery
1536 * @param low lowest address
1537 * @param high highest address
1539 * @return Return an error code or 0.
1541 * @ingroup krb5_address
1544 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1545 krb5_address_prefixlen_boundary(krb5_context context
,
1546 const krb5_address
*inaddr
,
1547 unsigned long prefixlen
,
1551 struct addr_operations
*a
= find_atype (inaddr
->addr_type
);
1552 if(a
!= NULL
&& a
->mask_boundary
!= NULL
)
1553 return (*a
->mask_boundary
)(context
, inaddr
, prefixlen
, low
, high
);
1554 krb5_set_error_message(context
, KRB5_PROG_ATYPE_NOSUPP
,
1555 N_("Address family %d doesn't support "
1556 "address mask operation", ""),
1558 return KRB5_PROG_ATYPE_NOSUPP
;