xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/addr_families.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: addr_families.c,v 1.1.1.2 2014/04/24 12:45:49 pettai Exp $	*/
2ebfedea0SLionel Sambuc 
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc  * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc  * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc  * All rights reserved.
7ebfedea0SLionel Sambuc  *
8ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
9ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
10ebfedea0SLionel Sambuc  * are met:
11ebfedea0SLionel Sambuc  *
12ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc  *
15ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17ebfedea0SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18ebfedea0SLionel Sambuc  *
19ebfedea0SLionel Sambuc  * 3. Neither the name of the Institute nor the names of its contributors
20ebfedea0SLionel Sambuc  *    may be used to endorse or promote products derived from this software
21ebfedea0SLionel Sambuc  *    without specific prior written permission.
22ebfedea0SLionel Sambuc  *
23ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ebfedea0SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ebfedea0SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ebfedea0SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ebfedea0SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ebfedea0SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ebfedea0SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ebfedea0SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ebfedea0SLionel Sambuc  * SUCH DAMAGE.
34ebfedea0SLionel Sambuc  */
35ebfedea0SLionel Sambuc 
36ebfedea0SLionel Sambuc #include "krb5_locl.h"
37ebfedea0SLionel Sambuc 
38ebfedea0SLionel Sambuc struct addr_operations {
39ebfedea0SLionel Sambuc     int af;
40ebfedea0SLionel Sambuc     krb5_address_type atype;
41ebfedea0SLionel Sambuc     size_t max_sockaddr_size;
42ebfedea0SLionel Sambuc     krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *);
43ebfedea0SLionel Sambuc     krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *);
44ebfedea0SLionel Sambuc     void (*addr2sockaddr)(const krb5_address *, struct sockaddr *,
45ebfedea0SLionel Sambuc 			  krb5_socklen_t *sa_size, int port);
46ebfedea0SLionel Sambuc     void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int);
47ebfedea0SLionel Sambuc     krb5_error_code (*h_addr2addr)(const char *, krb5_address *);
48ebfedea0SLionel Sambuc     krb5_boolean (*uninteresting)(const struct sockaddr *);
49ebfedea0SLionel Sambuc     krb5_boolean (*is_loopback)(const struct sockaddr *);
50ebfedea0SLionel Sambuc     void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int);
51ebfedea0SLionel Sambuc     int (*print_addr)(const krb5_address *, char *, size_t);
52ebfedea0SLionel Sambuc     int (*parse_addr)(krb5_context, const char*, krb5_address *);
53ebfedea0SLionel Sambuc     int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*);
54ebfedea0SLionel Sambuc     int (*free_addr)(krb5_context, krb5_address*);
55ebfedea0SLionel Sambuc     int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*);
56ebfedea0SLionel Sambuc     int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long,
57ebfedea0SLionel Sambuc 			 krb5_address*, krb5_address*);
58ebfedea0SLionel Sambuc };
59ebfedea0SLionel Sambuc 
60ebfedea0SLionel Sambuc /*
61ebfedea0SLionel Sambuc  * AF_INET - aka IPv4 implementation
62ebfedea0SLionel Sambuc  */
63ebfedea0SLionel Sambuc 
64ebfedea0SLionel Sambuc static krb5_error_code
ipv4_sockaddr2addr(const struct sockaddr * sa,krb5_address * a)65ebfedea0SLionel Sambuc ipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
66ebfedea0SLionel Sambuc {
67ebfedea0SLionel Sambuc     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
68ebfedea0SLionel Sambuc     unsigned char buf[4];
69ebfedea0SLionel Sambuc 
70ebfedea0SLionel Sambuc     a->addr_type = KRB5_ADDRESS_INET;
71ebfedea0SLionel Sambuc     memcpy (buf, &sin4->sin_addr, 4);
72ebfedea0SLionel Sambuc     return krb5_data_copy(&a->address, buf, 4);
73ebfedea0SLionel Sambuc }
74ebfedea0SLionel Sambuc 
75ebfedea0SLionel Sambuc static krb5_error_code
ipv4_sockaddr2port(const struct sockaddr * sa,int16_t * port)76ebfedea0SLionel Sambuc ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port)
77ebfedea0SLionel Sambuc {
78ebfedea0SLionel Sambuc     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
79ebfedea0SLionel Sambuc 
80ebfedea0SLionel Sambuc     *port = sin4->sin_port;
81ebfedea0SLionel Sambuc     return 0;
82ebfedea0SLionel Sambuc }
83ebfedea0SLionel Sambuc 
84ebfedea0SLionel Sambuc static void
ipv4_addr2sockaddr(const krb5_address * a,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)85ebfedea0SLionel Sambuc ipv4_addr2sockaddr (const krb5_address *a,
86ebfedea0SLionel Sambuc 		    struct sockaddr *sa,
87ebfedea0SLionel Sambuc 		    krb5_socklen_t *sa_size,
88ebfedea0SLionel Sambuc 		    int port)
89ebfedea0SLionel Sambuc {
90ebfedea0SLionel Sambuc     struct sockaddr_in tmp;
91ebfedea0SLionel Sambuc 
92ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
93ebfedea0SLionel Sambuc     tmp.sin_family = AF_INET;
94ebfedea0SLionel Sambuc     memcpy (&tmp.sin_addr, a->address.data, 4);
95ebfedea0SLionel Sambuc     tmp.sin_port = port;
96ebfedea0SLionel Sambuc     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
97ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
98ebfedea0SLionel Sambuc }
99ebfedea0SLionel Sambuc 
100ebfedea0SLionel Sambuc static void
ipv4_h_addr2sockaddr(const char * addr,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)101ebfedea0SLionel Sambuc ipv4_h_addr2sockaddr(const char *addr,
102ebfedea0SLionel Sambuc 		     struct sockaddr *sa,
103ebfedea0SLionel Sambuc 		     krb5_socklen_t *sa_size,
104ebfedea0SLionel Sambuc 		     int port)
105ebfedea0SLionel Sambuc {
106ebfedea0SLionel Sambuc     struct sockaddr_in tmp;
107ebfedea0SLionel Sambuc 
108ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
109ebfedea0SLionel Sambuc     tmp.sin_family = AF_INET;
110ebfedea0SLionel Sambuc     tmp.sin_port   = port;
111ebfedea0SLionel Sambuc     tmp.sin_addr   = *((const struct in_addr *)addr);
112ebfedea0SLionel Sambuc     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
113ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
114ebfedea0SLionel Sambuc }
115ebfedea0SLionel Sambuc 
116ebfedea0SLionel Sambuc static krb5_error_code
ipv4_h_addr2addr(const char * addr,krb5_address * a)117ebfedea0SLionel Sambuc ipv4_h_addr2addr (const char *addr,
118ebfedea0SLionel Sambuc 		  krb5_address *a)
119ebfedea0SLionel Sambuc {
120ebfedea0SLionel Sambuc     unsigned char buf[4];
121ebfedea0SLionel Sambuc 
122ebfedea0SLionel Sambuc     a->addr_type = KRB5_ADDRESS_INET;
123ebfedea0SLionel Sambuc     memcpy(buf, addr, 4);
124ebfedea0SLionel Sambuc     return krb5_data_copy(&a->address, buf, 4);
125ebfedea0SLionel Sambuc }
126ebfedea0SLionel Sambuc 
127ebfedea0SLionel Sambuc /*
128ebfedea0SLionel Sambuc  * Are there any addresses that should be considered `uninteresting'?
129ebfedea0SLionel Sambuc  */
130ebfedea0SLionel Sambuc 
131ebfedea0SLionel Sambuc static krb5_boolean
ipv4_uninteresting(const struct sockaddr * sa)132ebfedea0SLionel Sambuc ipv4_uninteresting (const struct sockaddr *sa)
133ebfedea0SLionel Sambuc {
134ebfedea0SLionel Sambuc     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
135ebfedea0SLionel Sambuc 
136ebfedea0SLionel Sambuc     if (sin4->sin_addr.s_addr == INADDR_ANY)
137ebfedea0SLionel Sambuc 	return TRUE;
138ebfedea0SLionel Sambuc 
139ebfedea0SLionel Sambuc     return FALSE;
140ebfedea0SLionel Sambuc }
141ebfedea0SLionel Sambuc 
142ebfedea0SLionel Sambuc static krb5_boolean
ipv4_is_loopback(const struct sockaddr * sa)143ebfedea0SLionel Sambuc ipv4_is_loopback (const struct sockaddr *sa)
144ebfedea0SLionel Sambuc {
145ebfedea0SLionel Sambuc     const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
146ebfedea0SLionel Sambuc 
147ebfedea0SLionel Sambuc     if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET)
148ebfedea0SLionel Sambuc 	return TRUE;
149ebfedea0SLionel Sambuc 
150ebfedea0SLionel Sambuc     return FALSE;
151ebfedea0SLionel Sambuc }
152ebfedea0SLionel Sambuc 
153ebfedea0SLionel Sambuc static void
ipv4_anyaddr(struct sockaddr * sa,krb5_socklen_t * sa_size,int port)154ebfedea0SLionel Sambuc ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
155ebfedea0SLionel Sambuc {
156ebfedea0SLionel Sambuc     struct sockaddr_in tmp;
157ebfedea0SLionel Sambuc 
158ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
159ebfedea0SLionel Sambuc     tmp.sin_family = AF_INET;
160ebfedea0SLionel Sambuc     tmp.sin_port   = port;
161ebfedea0SLionel Sambuc     tmp.sin_addr.s_addr = INADDR_ANY;
162ebfedea0SLionel Sambuc     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
163ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
164ebfedea0SLionel Sambuc }
165ebfedea0SLionel Sambuc 
166ebfedea0SLionel Sambuc static int
ipv4_print_addr(const krb5_address * addr,char * str,size_t len)167ebfedea0SLionel Sambuc ipv4_print_addr (const krb5_address *addr, char *str, size_t len)
168ebfedea0SLionel Sambuc {
169ebfedea0SLionel Sambuc     struct in_addr ia;
170ebfedea0SLionel Sambuc 
171ebfedea0SLionel Sambuc     memcpy (&ia, addr->address.data, 4);
172ebfedea0SLionel Sambuc 
173ebfedea0SLionel Sambuc     return snprintf (str, len, "IPv4:%s", inet_ntoa(ia));
174ebfedea0SLionel Sambuc }
175ebfedea0SLionel Sambuc 
176ebfedea0SLionel Sambuc static int
ipv4_parse_addr(krb5_context context,const char * address,krb5_address * addr)177ebfedea0SLionel Sambuc ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr)
178ebfedea0SLionel Sambuc {
179ebfedea0SLionel Sambuc     const char *p;
180ebfedea0SLionel Sambuc     struct in_addr a;
181ebfedea0SLionel Sambuc 
182ebfedea0SLionel Sambuc     p = strchr(address, ':');
183ebfedea0SLionel Sambuc     if(p) {
184ebfedea0SLionel Sambuc 	p++;
185ebfedea0SLionel Sambuc 	if(strncasecmp(address, "ip:", p - address) != 0 &&
186ebfedea0SLionel Sambuc 	   strncasecmp(address, "ip4:", p - address) != 0 &&
187ebfedea0SLionel Sambuc 	   strncasecmp(address, "ipv4:", p - address) != 0 &&
188ebfedea0SLionel Sambuc 	   strncasecmp(address, "inet:", p - address) != 0)
189ebfedea0SLionel Sambuc 	    return -1;
190ebfedea0SLionel Sambuc     } else
191ebfedea0SLionel Sambuc 	p = address;
192ebfedea0SLionel Sambuc     if(inet_aton(p, &a) == 0)
193ebfedea0SLionel Sambuc 	return -1;
194ebfedea0SLionel Sambuc     addr->addr_type = KRB5_ADDRESS_INET;
195ebfedea0SLionel Sambuc     if(krb5_data_alloc(&addr->address, 4) != 0)
196ebfedea0SLionel Sambuc 	return -1;
197ebfedea0SLionel Sambuc     _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length);
198ebfedea0SLionel Sambuc     return 0;
199ebfedea0SLionel Sambuc }
200ebfedea0SLionel Sambuc 
201ebfedea0SLionel Sambuc static int
ipv4_mask_boundary(krb5_context context,const krb5_address * inaddr,unsigned long len,krb5_address * low,krb5_address * high)202ebfedea0SLionel Sambuc ipv4_mask_boundary(krb5_context context, const krb5_address *inaddr,
203ebfedea0SLionel Sambuc 		   unsigned long len, krb5_address *low, krb5_address *high)
204ebfedea0SLionel Sambuc {
205ebfedea0SLionel Sambuc     unsigned long ia;
206ebfedea0SLionel Sambuc     uint32_t l, h, m = 0xffffffff;
207ebfedea0SLionel Sambuc 
208ebfedea0SLionel Sambuc     if (len > 32) {
209ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
210ebfedea0SLionel Sambuc 			       N_("IPv4 prefix too large (%ld)", "len"), len);
211ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
212ebfedea0SLionel Sambuc     }
213ebfedea0SLionel Sambuc     m = m << (32 - len);
214ebfedea0SLionel Sambuc 
215ebfedea0SLionel Sambuc     _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length);
216ebfedea0SLionel Sambuc 
217ebfedea0SLionel Sambuc     l = ia & m;
218ebfedea0SLionel Sambuc     h = l | ~m;
219ebfedea0SLionel Sambuc 
220ebfedea0SLionel Sambuc     low->addr_type = KRB5_ADDRESS_INET;
221ebfedea0SLionel Sambuc     if(krb5_data_alloc(&low->address, 4) != 0)
222ebfedea0SLionel Sambuc 	return -1;
223ebfedea0SLionel Sambuc     _krb5_put_int(low->address.data, l, low->address.length);
224ebfedea0SLionel Sambuc 
225ebfedea0SLionel Sambuc     high->addr_type = KRB5_ADDRESS_INET;
226ebfedea0SLionel Sambuc     if(krb5_data_alloc(&high->address, 4) != 0) {
227ebfedea0SLionel Sambuc 	krb5_free_address(context, low);
228ebfedea0SLionel Sambuc 	return -1;
229ebfedea0SLionel Sambuc     }
230ebfedea0SLionel Sambuc     _krb5_put_int(high->address.data, h, high->address.length);
231ebfedea0SLionel Sambuc 
232ebfedea0SLionel Sambuc     return 0;
233ebfedea0SLionel Sambuc }
234ebfedea0SLionel Sambuc 
235ebfedea0SLionel Sambuc 
236ebfedea0SLionel Sambuc /*
237ebfedea0SLionel Sambuc  * AF_INET6 - aka IPv6 implementation
238ebfedea0SLionel Sambuc  */
239ebfedea0SLionel Sambuc 
240ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
241ebfedea0SLionel Sambuc 
242ebfedea0SLionel Sambuc static krb5_error_code
ipv6_sockaddr2addr(const struct sockaddr * sa,krb5_address * a)243ebfedea0SLionel Sambuc ipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
244ebfedea0SLionel Sambuc {
245ebfedea0SLionel Sambuc     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
246ebfedea0SLionel Sambuc 
247ebfedea0SLionel Sambuc     if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
248ebfedea0SLionel Sambuc 	unsigned char buf[4];
249ebfedea0SLionel Sambuc 
250ebfedea0SLionel Sambuc 	a->addr_type      = KRB5_ADDRESS_INET;
251ebfedea0SLionel Sambuc #ifndef IN6_ADDR_V6_TO_V4
252ebfedea0SLionel Sambuc #ifdef IN6_EXTRACT_V4ADDR
253ebfedea0SLionel Sambuc #define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
254ebfedea0SLionel Sambuc #else
255ebfedea0SLionel Sambuc #define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
256ebfedea0SLionel Sambuc #endif
257ebfedea0SLionel Sambuc #endif
258ebfedea0SLionel Sambuc 	memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4);
259ebfedea0SLionel Sambuc 	return krb5_data_copy(&a->address, buf, 4);
260ebfedea0SLionel Sambuc     } else {
261ebfedea0SLionel Sambuc 	a->addr_type = KRB5_ADDRESS_INET6;
262ebfedea0SLionel Sambuc 	return krb5_data_copy(&a->address,
263ebfedea0SLionel Sambuc 			      &sin6->sin6_addr,
264ebfedea0SLionel Sambuc 			      sizeof(sin6->sin6_addr));
265ebfedea0SLionel Sambuc     }
266ebfedea0SLionel Sambuc }
267ebfedea0SLionel Sambuc 
268ebfedea0SLionel Sambuc static krb5_error_code
ipv6_sockaddr2port(const struct sockaddr * sa,int16_t * port)269ebfedea0SLionel Sambuc ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port)
270ebfedea0SLionel Sambuc {
271ebfedea0SLionel Sambuc     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
272ebfedea0SLionel Sambuc 
273ebfedea0SLionel Sambuc     *port = sin6->sin6_port;
274ebfedea0SLionel Sambuc     return 0;
275ebfedea0SLionel Sambuc }
276ebfedea0SLionel Sambuc 
277ebfedea0SLionel Sambuc static void
ipv6_addr2sockaddr(const krb5_address * a,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)278ebfedea0SLionel Sambuc ipv6_addr2sockaddr (const krb5_address *a,
279ebfedea0SLionel Sambuc 		    struct sockaddr *sa,
280ebfedea0SLionel Sambuc 		    krb5_socklen_t *sa_size,
281ebfedea0SLionel Sambuc 		    int port)
282ebfedea0SLionel Sambuc {
283ebfedea0SLionel Sambuc     struct sockaddr_in6 tmp;
284ebfedea0SLionel Sambuc 
285ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
286ebfedea0SLionel Sambuc     tmp.sin6_family = AF_INET6;
287ebfedea0SLionel Sambuc     memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr));
288ebfedea0SLionel Sambuc     tmp.sin6_port = port;
289ebfedea0SLionel Sambuc     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
290ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
291ebfedea0SLionel Sambuc }
292ebfedea0SLionel Sambuc 
293ebfedea0SLionel Sambuc static void
ipv6_h_addr2sockaddr(const char * addr,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)294ebfedea0SLionel Sambuc ipv6_h_addr2sockaddr(const char *addr,
295ebfedea0SLionel Sambuc 		     struct sockaddr *sa,
296ebfedea0SLionel Sambuc 		     krb5_socklen_t *sa_size,
297ebfedea0SLionel Sambuc 		     int port)
298ebfedea0SLionel Sambuc {
299ebfedea0SLionel Sambuc     struct sockaddr_in6 tmp;
300ebfedea0SLionel Sambuc 
301ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
302ebfedea0SLionel Sambuc     tmp.sin6_family = AF_INET6;
303ebfedea0SLionel Sambuc     tmp.sin6_port   = port;
304ebfedea0SLionel Sambuc     tmp.sin6_addr   = *((const struct in6_addr *)addr);
305ebfedea0SLionel Sambuc     memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
306ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
307ebfedea0SLionel Sambuc }
308ebfedea0SLionel Sambuc 
309ebfedea0SLionel Sambuc static krb5_error_code
ipv6_h_addr2addr(const char * addr,krb5_address * a)310ebfedea0SLionel Sambuc ipv6_h_addr2addr (const char *addr,
311ebfedea0SLionel Sambuc 		  krb5_address *a)
312ebfedea0SLionel Sambuc {
313ebfedea0SLionel Sambuc     a->addr_type = KRB5_ADDRESS_INET6;
314ebfedea0SLionel Sambuc     return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr));
315ebfedea0SLionel Sambuc }
316ebfedea0SLionel Sambuc 
317ebfedea0SLionel Sambuc /*
318ebfedea0SLionel Sambuc  *
319ebfedea0SLionel Sambuc  */
320ebfedea0SLionel Sambuc 
321ebfedea0SLionel Sambuc static krb5_boolean
ipv6_uninteresting(const struct sockaddr * sa)322ebfedea0SLionel Sambuc ipv6_uninteresting (const struct sockaddr *sa)
323ebfedea0SLionel Sambuc {
324ebfedea0SLionel Sambuc     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
325ebfedea0SLionel Sambuc     const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
326ebfedea0SLionel Sambuc 
327ebfedea0SLionel Sambuc     return IN6_IS_ADDR_LINKLOCAL(in6)
328ebfedea0SLionel Sambuc 	|| IN6_IS_ADDR_V4COMPAT(in6);
329ebfedea0SLionel Sambuc }
330ebfedea0SLionel Sambuc 
331ebfedea0SLionel Sambuc static krb5_boolean
ipv6_is_loopback(const struct sockaddr * sa)332ebfedea0SLionel Sambuc ipv6_is_loopback (const struct sockaddr *sa)
333ebfedea0SLionel Sambuc {
334ebfedea0SLionel Sambuc     const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
335ebfedea0SLionel Sambuc     const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
336ebfedea0SLionel Sambuc 
337ebfedea0SLionel Sambuc     return (IN6_IS_ADDR_LOOPBACK(in6));
338ebfedea0SLionel Sambuc }
339ebfedea0SLionel Sambuc 
340ebfedea0SLionel Sambuc static void
ipv6_anyaddr(struct sockaddr * sa,krb5_socklen_t * sa_size,int port)341ebfedea0SLionel Sambuc ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
342ebfedea0SLionel Sambuc {
343ebfedea0SLionel Sambuc     struct sockaddr_in6 tmp;
344ebfedea0SLionel Sambuc 
345ebfedea0SLionel Sambuc     memset (&tmp, 0, sizeof(tmp));
346ebfedea0SLionel Sambuc     tmp.sin6_family = AF_INET6;
347ebfedea0SLionel Sambuc     tmp.sin6_port   = port;
348ebfedea0SLionel Sambuc     tmp.sin6_addr   = in6addr_any;
349ebfedea0SLionel Sambuc     *sa_size = sizeof(tmp);
350ebfedea0SLionel Sambuc }
351ebfedea0SLionel Sambuc 
352ebfedea0SLionel Sambuc static int
ipv6_print_addr(const krb5_address * addr,char * str,size_t len)353ebfedea0SLionel Sambuc ipv6_print_addr (const krb5_address *addr, char *str, size_t len)
354ebfedea0SLionel Sambuc {
355ebfedea0SLionel Sambuc     char buf[128], buf2[3];
356ebfedea0SLionel Sambuc     if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL)
357ebfedea0SLionel Sambuc 	{
358ebfedea0SLionel Sambuc 	    /* XXX this is pretty ugly, but better than abort() */
359*0a6a1f1dSLionel Sambuc 	    size_t i;
360ebfedea0SLionel Sambuc 	    unsigned char *p = addr->address.data;
361ebfedea0SLionel Sambuc 	    buf[0] = '\0';
362ebfedea0SLionel Sambuc 	    for(i = 0; i < addr->address.length; i++) {
363ebfedea0SLionel Sambuc 		snprintf(buf2, sizeof(buf2), "%02x", p[i]);
364ebfedea0SLionel Sambuc 		if(i > 0 && (i & 1) == 0)
365ebfedea0SLionel Sambuc 		    strlcat(buf, ":", sizeof(buf));
366ebfedea0SLionel Sambuc 		strlcat(buf, buf2, sizeof(buf));
367ebfedea0SLionel Sambuc 	    }
368ebfedea0SLionel Sambuc 	}
369ebfedea0SLionel Sambuc     return snprintf(str, len, "IPv6:%s", buf);
370ebfedea0SLionel Sambuc }
371ebfedea0SLionel Sambuc 
372ebfedea0SLionel Sambuc static int
ipv6_parse_addr(krb5_context context,const char * address,krb5_address * addr)373ebfedea0SLionel Sambuc ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr)
374ebfedea0SLionel Sambuc {
375ebfedea0SLionel Sambuc     int ret;
376ebfedea0SLionel Sambuc     struct in6_addr in6;
377ebfedea0SLionel Sambuc     const char *p;
378ebfedea0SLionel Sambuc 
379ebfedea0SLionel Sambuc     p = strchr(address, ':');
380ebfedea0SLionel Sambuc     if(p) {
381ebfedea0SLionel Sambuc 	p++;
382ebfedea0SLionel Sambuc 	if(strncasecmp(address, "ip6:", p - address) == 0 ||
383ebfedea0SLionel Sambuc 	   strncasecmp(address, "ipv6:", p - address) == 0 ||
384ebfedea0SLionel Sambuc 	   strncasecmp(address, "inet6:", p - address) == 0)
385ebfedea0SLionel Sambuc 	    address = p;
386ebfedea0SLionel Sambuc     }
387ebfedea0SLionel Sambuc 
388ebfedea0SLionel Sambuc     ret = inet_pton(AF_INET6, address, &in6.s6_addr);
389ebfedea0SLionel Sambuc     if(ret == 1) {
390ebfedea0SLionel Sambuc 	addr->addr_type = KRB5_ADDRESS_INET6;
391ebfedea0SLionel Sambuc 	ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr));
392ebfedea0SLionel Sambuc 	if (ret)
393ebfedea0SLionel Sambuc 	    return -1;
394ebfedea0SLionel Sambuc 	memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr));
395ebfedea0SLionel Sambuc 	return 0;
396ebfedea0SLionel Sambuc     }
397ebfedea0SLionel Sambuc     return -1;
398ebfedea0SLionel Sambuc }
399ebfedea0SLionel Sambuc 
400ebfedea0SLionel Sambuc static int
ipv6_mask_boundary(krb5_context context,const krb5_address * inaddr,unsigned long len,krb5_address * low,krb5_address * high)401ebfedea0SLionel Sambuc ipv6_mask_boundary(krb5_context context, const krb5_address *inaddr,
402ebfedea0SLionel Sambuc 		   unsigned long len, krb5_address *low, krb5_address *high)
403ebfedea0SLionel Sambuc {
404ebfedea0SLionel Sambuc     struct in6_addr addr, laddr, haddr;
405ebfedea0SLionel Sambuc     uint32_t m;
406ebfedea0SLionel Sambuc     int i, sub_len;
407ebfedea0SLionel Sambuc 
408ebfedea0SLionel Sambuc     if (len > 128) {
409ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
410ebfedea0SLionel Sambuc 			       N_("IPv6 prefix too large (%ld)", "length"), len);
411ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
412ebfedea0SLionel Sambuc     }
413ebfedea0SLionel Sambuc 
414ebfedea0SLionel Sambuc     if (inaddr->address.length != sizeof(addr)) {
415ebfedea0SLionel Sambuc 	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
416ebfedea0SLionel Sambuc 			       N_("IPv6 addr bad length", ""));
417ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
418ebfedea0SLionel Sambuc     }
419ebfedea0SLionel Sambuc 
420ebfedea0SLionel Sambuc     memcpy(&addr, inaddr->address.data, inaddr->address.length);
421ebfedea0SLionel Sambuc 
422ebfedea0SLionel Sambuc     for (i = 0; i < 16; i++) {
423ebfedea0SLionel Sambuc 	sub_len = min(8, len);
424ebfedea0SLionel Sambuc 
425ebfedea0SLionel Sambuc 	m = 0xff << (8 - sub_len);
426ebfedea0SLionel Sambuc 
427ebfedea0SLionel Sambuc 	laddr.s6_addr[i] = addr.s6_addr[i] & m;
428ebfedea0SLionel Sambuc 	haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m;
429ebfedea0SLionel Sambuc 
430ebfedea0SLionel Sambuc 	if (len > 8)
431ebfedea0SLionel Sambuc 	    len -= 8;
432ebfedea0SLionel Sambuc 	else
433ebfedea0SLionel Sambuc 	    len = 0;
434ebfedea0SLionel Sambuc     }
435ebfedea0SLionel Sambuc 
436ebfedea0SLionel Sambuc     low->addr_type = KRB5_ADDRESS_INET6;
437ebfedea0SLionel Sambuc     if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0)
438ebfedea0SLionel Sambuc 	return -1;
439ebfedea0SLionel Sambuc     memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr));
440ebfedea0SLionel Sambuc 
441ebfedea0SLionel Sambuc     high->addr_type = KRB5_ADDRESS_INET6;
442ebfedea0SLionel Sambuc     if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) {
443ebfedea0SLionel Sambuc 	krb5_free_address(context, low);
444ebfedea0SLionel Sambuc 	return -1;
445ebfedea0SLionel Sambuc     }
446ebfedea0SLionel Sambuc     memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr));
447ebfedea0SLionel Sambuc 
448ebfedea0SLionel Sambuc     return 0;
449ebfedea0SLionel Sambuc }
450ebfedea0SLionel Sambuc 
451ebfedea0SLionel Sambuc #endif /* IPv6 */
452ebfedea0SLionel Sambuc 
453ebfedea0SLionel Sambuc #ifndef HEIMDAL_SMALLER
454ebfedea0SLionel Sambuc 
455ebfedea0SLionel Sambuc /*
456ebfedea0SLionel Sambuc  * table
457ebfedea0SLionel Sambuc  */
458ebfedea0SLionel Sambuc 
459ebfedea0SLionel Sambuc #define KRB5_ADDRESS_ARANGE	(-100)
460ebfedea0SLionel Sambuc 
461ebfedea0SLionel Sambuc struct arange {
462ebfedea0SLionel Sambuc     krb5_address low;
463ebfedea0SLionel Sambuc     krb5_address high;
464ebfedea0SLionel Sambuc };
465ebfedea0SLionel Sambuc 
466ebfedea0SLionel Sambuc static int
arange_parse_addr(krb5_context context,const char * address,krb5_address * addr)467ebfedea0SLionel Sambuc arange_parse_addr (krb5_context context,
468ebfedea0SLionel Sambuc 		   const char *address, krb5_address *addr)
469ebfedea0SLionel Sambuc {
470ebfedea0SLionel Sambuc     char buf[1024], *p;
471ebfedea0SLionel Sambuc     krb5_address low0, high0;
472ebfedea0SLionel Sambuc     struct arange *a;
473ebfedea0SLionel Sambuc     krb5_error_code ret;
474ebfedea0SLionel Sambuc 
475ebfedea0SLionel Sambuc     if(strncasecmp(address, "RANGE:", 6) != 0)
476ebfedea0SLionel Sambuc 	return -1;
477ebfedea0SLionel Sambuc 
478ebfedea0SLionel Sambuc     address += 6;
479ebfedea0SLionel Sambuc 
480ebfedea0SLionel Sambuc     p = strrchr(address, '/');
481ebfedea0SLionel Sambuc     if (p) {
482ebfedea0SLionel Sambuc 	krb5_addresses addrmask;
483ebfedea0SLionel Sambuc 	char *q;
484ebfedea0SLionel Sambuc 	long num;
485ebfedea0SLionel Sambuc 
486ebfedea0SLionel Sambuc 	if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf))
487ebfedea0SLionel Sambuc 	    return -1;
488ebfedea0SLionel Sambuc 	buf[p - address] = '\0';
489ebfedea0SLionel Sambuc 	ret = krb5_parse_address(context, buf, &addrmask);
490ebfedea0SLionel Sambuc 	if (ret)
491ebfedea0SLionel Sambuc 	    return ret;
492ebfedea0SLionel Sambuc 	if(addrmask.len != 1) {
493ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &addrmask);
494ebfedea0SLionel Sambuc 	    return -1;
495ebfedea0SLionel Sambuc 	}
496ebfedea0SLionel Sambuc 
497ebfedea0SLionel Sambuc 	address += p - address + 1;
498ebfedea0SLionel Sambuc 
499ebfedea0SLionel Sambuc 	num = strtol(address, &q, 10);
500ebfedea0SLionel Sambuc 	if (q == address || *q != '\0' || num < 0) {
501ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &addrmask);
502ebfedea0SLionel Sambuc 	    return -1;
503ebfedea0SLionel Sambuc 	}
504ebfedea0SLionel Sambuc 
505ebfedea0SLionel Sambuc 	ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num,
506ebfedea0SLionel Sambuc 					      &low0, &high0);
507ebfedea0SLionel Sambuc 	krb5_free_addresses(context, &addrmask);
508ebfedea0SLionel Sambuc 	if (ret)
509ebfedea0SLionel Sambuc 	    return ret;
510ebfedea0SLionel Sambuc 
511ebfedea0SLionel Sambuc     } else {
512ebfedea0SLionel Sambuc 	krb5_addresses low, high;
513ebfedea0SLionel Sambuc 
514ebfedea0SLionel Sambuc 	strsep_copy(&address, "-", buf, sizeof(buf));
515ebfedea0SLionel Sambuc 	ret = krb5_parse_address(context, buf, &low);
516ebfedea0SLionel Sambuc 	if(ret)
517ebfedea0SLionel Sambuc 	    return ret;
518ebfedea0SLionel Sambuc 	if(low.len != 1) {
519ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &low);
520ebfedea0SLionel Sambuc 	    return -1;
521ebfedea0SLionel Sambuc 	}
522ebfedea0SLionel Sambuc 
523ebfedea0SLionel Sambuc 	strsep_copy(&address, "-", buf, sizeof(buf));
524ebfedea0SLionel Sambuc 	ret = krb5_parse_address(context, buf, &high);
525ebfedea0SLionel Sambuc 	if(ret) {
526ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &low);
527ebfedea0SLionel Sambuc 	    return ret;
528ebfedea0SLionel Sambuc 	}
529ebfedea0SLionel Sambuc 
530ebfedea0SLionel Sambuc 	if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) {
531ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &low);
532ebfedea0SLionel Sambuc 	    krb5_free_addresses(context, &high);
533ebfedea0SLionel Sambuc 	    return -1;
534ebfedea0SLionel Sambuc 	}
535ebfedea0SLionel Sambuc 
536ebfedea0SLionel Sambuc 	ret = krb5_copy_address(context, &high.val[0], &high0);
537ebfedea0SLionel Sambuc 	if (ret == 0) {
538ebfedea0SLionel Sambuc 	    ret = krb5_copy_address(context, &low.val[0], &low0);
539ebfedea0SLionel Sambuc 	    if (ret)
540ebfedea0SLionel Sambuc 		krb5_free_address(context, &high0);
541ebfedea0SLionel Sambuc 	}
542ebfedea0SLionel Sambuc 	krb5_free_addresses(context, &low);
543ebfedea0SLionel Sambuc 	krb5_free_addresses(context, &high);
544ebfedea0SLionel Sambuc 	if (ret)
545ebfedea0SLionel Sambuc 	    return ret;
546ebfedea0SLionel Sambuc     }
547ebfedea0SLionel Sambuc 
548ebfedea0SLionel Sambuc     krb5_data_alloc(&addr->address, sizeof(*a));
549ebfedea0SLionel Sambuc     addr->addr_type = KRB5_ADDRESS_ARANGE;
550ebfedea0SLionel Sambuc     a = addr->address.data;
551ebfedea0SLionel Sambuc 
552ebfedea0SLionel Sambuc     if(krb5_address_order(context, &low0, &high0) < 0) {
553ebfedea0SLionel Sambuc 	a->low = low0;
554ebfedea0SLionel Sambuc 	a->high = high0;
555ebfedea0SLionel Sambuc     } else {
556ebfedea0SLionel Sambuc 	a->low = high0;
557ebfedea0SLionel Sambuc 	a->high = low0;
558ebfedea0SLionel Sambuc     }
559ebfedea0SLionel Sambuc     return 0;
560ebfedea0SLionel Sambuc }
561ebfedea0SLionel Sambuc 
562ebfedea0SLionel Sambuc static int
arange_free(krb5_context context,krb5_address * addr)563ebfedea0SLionel Sambuc arange_free (krb5_context context, krb5_address *addr)
564ebfedea0SLionel Sambuc {
565ebfedea0SLionel Sambuc     struct arange *a;
566ebfedea0SLionel Sambuc     a = addr->address.data;
567ebfedea0SLionel Sambuc     krb5_free_address(context, &a->low);
568ebfedea0SLionel Sambuc     krb5_free_address(context, &a->high);
569ebfedea0SLionel Sambuc     krb5_data_free(&addr->address);
570ebfedea0SLionel Sambuc     return 0;
571ebfedea0SLionel Sambuc }
572ebfedea0SLionel Sambuc 
573ebfedea0SLionel Sambuc 
574ebfedea0SLionel Sambuc static int
arange_copy(krb5_context context,const krb5_address * inaddr,krb5_address * outaddr)575ebfedea0SLionel Sambuc arange_copy (krb5_context context, const krb5_address *inaddr,
576ebfedea0SLionel Sambuc 	     krb5_address *outaddr)
577ebfedea0SLionel Sambuc {
578ebfedea0SLionel Sambuc     krb5_error_code ret;
579ebfedea0SLionel Sambuc     struct arange *i, *o;
580ebfedea0SLionel Sambuc 
581ebfedea0SLionel Sambuc     outaddr->addr_type = KRB5_ADDRESS_ARANGE;
582ebfedea0SLionel Sambuc     ret = krb5_data_alloc(&outaddr->address, sizeof(*o));
583ebfedea0SLionel Sambuc     if(ret)
584ebfedea0SLionel Sambuc 	return ret;
585ebfedea0SLionel Sambuc     i = inaddr->address.data;
586ebfedea0SLionel Sambuc     o = outaddr->address.data;
587ebfedea0SLionel Sambuc     ret = krb5_copy_address(context, &i->low, &o->low);
588ebfedea0SLionel Sambuc     if(ret) {
589ebfedea0SLionel Sambuc 	krb5_data_free(&outaddr->address);
590ebfedea0SLionel Sambuc 	return ret;
591ebfedea0SLionel Sambuc     }
592ebfedea0SLionel Sambuc     ret = krb5_copy_address(context, &i->high, &o->high);
593ebfedea0SLionel Sambuc     if(ret) {
594ebfedea0SLionel Sambuc 	krb5_free_address(context, &o->low);
595ebfedea0SLionel Sambuc 	krb5_data_free(&outaddr->address);
596ebfedea0SLionel Sambuc 	return ret;
597ebfedea0SLionel Sambuc     }
598ebfedea0SLionel Sambuc     return 0;
599ebfedea0SLionel Sambuc }
600ebfedea0SLionel Sambuc 
601ebfedea0SLionel Sambuc static int
arange_print_addr(const krb5_address * addr,char * str,size_t len)602ebfedea0SLionel Sambuc arange_print_addr (const krb5_address *addr, char *str, size_t len)
603ebfedea0SLionel Sambuc {
604ebfedea0SLionel Sambuc     struct arange *a;
605ebfedea0SLionel Sambuc     krb5_error_code ret;
606ebfedea0SLionel Sambuc     size_t l, size, ret_len;
607ebfedea0SLionel Sambuc 
608ebfedea0SLionel Sambuc     a = addr->address.data;
609ebfedea0SLionel Sambuc 
610ebfedea0SLionel Sambuc     l = strlcpy(str, "RANGE:", len);
611ebfedea0SLionel Sambuc     ret_len = l;
612ebfedea0SLionel Sambuc     if (l > len)
613ebfedea0SLionel Sambuc 	l = len;
614ebfedea0SLionel Sambuc     size = l;
615ebfedea0SLionel Sambuc 
616ebfedea0SLionel Sambuc     ret = krb5_print_address (&a->low, str + size, len - size, &l);
617ebfedea0SLionel Sambuc     if (ret)
618ebfedea0SLionel Sambuc 	return ret;
619ebfedea0SLionel Sambuc     ret_len += l;
620ebfedea0SLionel Sambuc     if (len - size > l)
621ebfedea0SLionel Sambuc 	size += l;
622ebfedea0SLionel Sambuc     else
623ebfedea0SLionel Sambuc 	size = len;
624ebfedea0SLionel Sambuc 
625ebfedea0SLionel Sambuc     l = strlcat(str + size, "-", len - size);
626ebfedea0SLionel Sambuc     ret_len += l;
627ebfedea0SLionel Sambuc     if (len - size > l)
628ebfedea0SLionel Sambuc 	size += l;
629ebfedea0SLionel Sambuc     else
630ebfedea0SLionel Sambuc 	size = len;
631ebfedea0SLionel Sambuc 
632ebfedea0SLionel Sambuc     ret = krb5_print_address (&a->high, str + size, len - size, &l);
633ebfedea0SLionel Sambuc     if (ret)
634ebfedea0SLionel Sambuc 	return ret;
635ebfedea0SLionel Sambuc     ret_len += l;
636ebfedea0SLionel Sambuc 
637ebfedea0SLionel Sambuc     return ret_len;
638ebfedea0SLionel Sambuc }
639ebfedea0SLionel Sambuc 
640ebfedea0SLionel Sambuc static int
arange_order_addr(krb5_context context,const krb5_address * addr1,const krb5_address * addr2)641ebfedea0SLionel Sambuc arange_order_addr(krb5_context context,
642ebfedea0SLionel Sambuc 		  const krb5_address *addr1,
643ebfedea0SLionel Sambuc 		  const krb5_address *addr2)
644ebfedea0SLionel Sambuc {
645ebfedea0SLionel Sambuc     int tmp1, tmp2, sign;
646ebfedea0SLionel Sambuc     struct arange *a;
647ebfedea0SLionel Sambuc     const krb5_address *a2;
648ebfedea0SLionel Sambuc 
649ebfedea0SLionel Sambuc     if(addr1->addr_type == KRB5_ADDRESS_ARANGE) {
650ebfedea0SLionel Sambuc 	a = addr1->address.data;
651ebfedea0SLionel Sambuc 	a2 = addr2;
652ebfedea0SLionel Sambuc 	sign = 1;
653ebfedea0SLionel Sambuc     } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) {
654ebfedea0SLionel Sambuc 	a = addr2->address.data;
655ebfedea0SLionel Sambuc 	a2 = addr1;
656ebfedea0SLionel Sambuc 	sign = -1;
657*0a6a1f1dSLionel Sambuc     } else {
658ebfedea0SLionel Sambuc 	abort();
659*0a6a1f1dSLionel Sambuc         UNREACHABLE(return 0);
660*0a6a1f1dSLionel Sambuc     }
661ebfedea0SLionel Sambuc 
662ebfedea0SLionel Sambuc     if(a2->addr_type == KRB5_ADDRESS_ARANGE) {
663ebfedea0SLionel Sambuc 	struct arange *b = a2->address.data;
664ebfedea0SLionel Sambuc 	tmp1 = krb5_address_order(context, &a->low, &b->low);
665ebfedea0SLionel Sambuc 	if(tmp1 != 0)
666ebfedea0SLionel Sambuc 	    return sign * tmp1;
667ebfedea0SLionel Sambuc 	return sign * krb5_address_order(context, &a->high, &b->high);
668ebfedea0SLionel Sambuc     } else if(a2->addr_type == a->low.addr_type) {
669ebfedea0SLionel Sambuc 	tmp1 = krb5_address_order(context, &a->low, a2);
670ebfedea0SLionel Sambuc 	if(tmp1 > 0)
671ebfedea0SLionel Sambuc 	    return sign;
672ebfedea0SLionel Sambuc 	tmp2 = krb5_address_order(context, &a->high, a2);
673ebfedea0SLionel Sambuc 	if(tmp2 < 0)
674ebfedea0SLionel Sambuc 	    return -sign;
675ebfedea0SLionel Sambuc 	return 0;
676ebfedea0SLionel Sambuc     } else {
677ebfedea0SLionel Sambuc 	return sign * (addr1->addr_type - addr2->addr_type);
678ebfedea0SLionel Sambuc     }
679ebfedea0SLionel Sambuc }
680ebfedea0SLionel Sambuc 
681ebfedea0SLionel Sambuc #endif /* HEIMDAL_SMALLER */
682ebfedea0SLionel Sambuc 
683ebfedea0SLionel Sambuc static int
addrport_print_addr(const krb5_address * addr,char * str,size_t len)684ebfedea0SLionel Sambuc addrport_print_addr (const krb5_address *addr, char *str, size_t len)
685ebfedea0SLionel Sambuc {
686ebfedea0SLionel Sambuc     krb5_error_code ret;
687ebfedea0SLionel Sambuc     krb5_address addr1, addr2;
688ebfedea0SLionel Sambuc     uint16_t port = 0;
689ebfedea0SLionel Sambuc     size_t ret_len = 0, l, size = 0;
690ebfedea0SLionel Sambuc     krb5_storage *sp;
691ebfedea0SLionel Sambuc 
692ebfedea0SLionel Sambuc     sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address));
693ebfedea0SLionel Sambuc     if (sp == NULL)
694ebfedea0SLionel Sambuc         return ENOMEM;
695ebfedea0SLionel Sambuc 
696ebfedea0SLionel Sambuc     /* for totally obscure reasons, these are not in network byteorder */
697ebfedea0SLionel Sambuc     krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
698ebfedea0SLionel Sambuc 
699ebfedea0SLionel Sambuc     krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */
700ebfedea0SLionel Sambuc     krb5_ret_address(sp, &addr1);
701ebfedea0SLionel Sambuc 
702ebfedea0SLionel Sambuc     krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */
703ebfedea0SLionel Sambuc     krb5_ret_address(sp, &addr2);
704ebfedea0SLionel Sambuc     krb5_storage_free(sp);
705ebfedea0SLionel Sambuc     if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) {
706ebfedea0SLionel Sambuc 	unsigned long value;
707ebfedea0SLionel Sambuc 	_krb5_get_int(addr2.address.data, &value, 2);
708ebfedea0SLionel Sambuc 	port = value;
709ebfedea0SLionel Sambuc     }
710ebfedea0SLionel Sambuc     l = strlcpy(str, "ADDRPORT:", len);
711ebfedea0SLionel Sambuc     ret_len += l;
712ebfedea0SLionel Sambuc     if (len > l)
713ebfedea0SLionel Sambuc 	size += l;
714ebfedea0SLionel Sambuc     else
715ebfedea0SLionel Sambuc 	size = len;
716ebfedea0SLionel Sambuc 
717ebfedea0SLionel Sambuc     ret = krb5_print_address(&addr1, str + size, len - size, &l);
718ebfedea0SLionel Sambuc     if (ret)
719ebfedea0SLionel Sambuc 	return ret;
720ebfedea0SLionel Sambuc     ret_len += l;
721ebfedea0SLionel Sambuc     if (len - size > l)
722ebfedea0SLionel Sambuc 	size += l;
723ebfedea0SLionel Sambuc     else
724ebfedea0SLionel Sambuc 	size = len;
725ebfedea0SLionel Sambuc 
726ebfedea0SLionel Sambuc     ret = snprintf(str + size, len - size, ",PORT=%u", port);
727ebfedea0SLionel Sambuc     if (ret < 0)
728ebfedea0SLionel Sambuc 	return EINVAL;
729ebfedea0SLionel Sambuc     ret_len += ret;
730ebfedea0SLionel Sambuc     return ret_len;
731ebfedea0SLionel Sambuc }
732ebfedea0SLionel Sambuc 
733ebfedea0SLionel Sambuc static struct addr_operations at[] = {
734*0a6a1f1dSLionel Sambuc     {
735*0a6a1f1dSLionel Sambuc 	AF_INET,	KRB5_ADDRESS_INET, sizeof(struct sockaddr_in),
736ebfedea0SLionel Sambuc 	ipv4_sockaddr2addr,
737ebfedea0SLionel Sambuc 	ipv4_sockaddr2port,
738ebfedea0SLionel Sambuc 	ipv4_addr2sockaddr,
739ebfedea0SLionel Sambuc 	ipv4_h_addr2sockaddr,
740ebfedea0SLionel Sambuc 	ipv4_h_addr2addr,
741*0a6a1f1dSLionel Sambuc 	ipv4_uninteresting,
742*0a6a1f1dSLionel Sambuc 	ipv4_is_loopback,
743*0a6a1f1dSLionel Sambuc 	ipv4_anyaddr,
744*0a6a1f1dSLionel Sambuc 	ipv4_print_addr,
745*0a6a1f1dSLionel Sambuc 	ipv4_parse_addr,
746*0a6a1f1dSLionel Sambuc 	NULL,
747*0a6a1f1dSLionel Sambuc 	NULL,
748*0a6a1f1dSLionel Sambuc 	NULL,
749*0a6a1f1dSLionel Sambuc      ipv4_mask_boundary
750*0a6a1f1dSLionel Sambuc     },
751ebfedea0SLionel Sambuc #ifdef HAVE_IPV6
752*0a6a1f1dSLionel Sambuc     {
753*0a6a1f1dSLionel Sambuc 	AF_INET6,	KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6),
754ebfedea0SLionel Sambuc 	ipv6_sockaddr2addr,
755ebfedea0SLionel Sambuc 	ipv6_sockaddr2port,
756ebfedea0SLionel Sambuc 	ipv6_addr2sockaddr,
757ebfedea0SLionel Sambuc 	ipv6_h_addr2sockaddr,
758ebfedea0SLionel Sambuc 	ipv6_h_addr2addr,
759*0a6a1f1dSLionel Sambuc 	ipv6_uninteresting,
760*0a6a1f1dSLionel Sambuc 	ipv6_is_loopback,
761*0a6a1f1dSLionel Sambuc 	ipv6_anyaddr,
762*0a6a1f1dSLionel Sambuc 	ipv6_print_addr,
763*0a6a1f1dSLionel Sambuc 	ipv6_parse_addr,
764*0a6a1f1dSLionel Sambuc 	NULL,
765*0a6a1f1dSLionel Sambuc 	NULL,
766*0a6a1f1dSLionel Sambuc 	NULL,
767*0a6a1f1dSLionel Sambuc 	ipv6_mask_boundary
768*0a6a1f1dSLionel Sambuc     } ,
769ebfedea0SLionel Sambuc #endif
770ebfedea0SLionel Sambuc #ifndef HEIMDAL_SMALLER
771ebfedea0SLionel Sambuc     /* fake address type */
772*0a6a1f1dSLionel Sambuc     {
773*0a6a1f1dSLionel Sambuc 	KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange),
774*0a6a1f1dSLionel Sambuc 	NULL,
775*0a6a1f1dSLionel Sambuc 	NULL,
776*0a6a1f1dSLionel Sambuc 	NULL,
777*0a6a1f1dSLionel Sambuc 	NULL,
778*0a6a1f1dSLionel Sambuc 	NULL,
779*0a6a1f1dSLionel Sambuc 	NULL,
780*0a6a1f1dSLionel Sambuc 	NULL,
781*0a6a1f1dSLionel Sambuc 	NULL,
782*0a6a1f1dSLionel Sambuc 	arange_print_addr,
783*0a6a1f1dSLionel Sambuc 	arange_parse_addr,
784*0a6a1f1dSLionel Sambuc 	arange_order_addr,
785*0a6a1f1dSLionel Sambuc 	arange_free,
786*0a6a1f1dSLionel Sambuc 	arange_copy,
787*0a6a1f1dSLionel Sambuc 	NULL
788*0a6a1f1dSLionel Sambuc     },
789ebfedea0SLionel Sambuc #endif
790*0a6a1f1dSLionel Sambuc     {
791*0a6a1f1dSLionel Sambuc 	KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0,
792*0a6a1f1dSLionel Sambuc 	NULL,
793*0a6a1f1dSLionel Sambuc 	NULL,
794*0a6a1f1dSLionel Sambuc 	NULL,
795*0a6a1f1dSLionel Sambuc 	NULL,
796*0a6a1f1dSLionel Sambuc 	NULL,
797*0a6a1f1dSLionel Sambuc 	NULL,
798*0a6a1f1dSLionel Sambuc 	NULL,
799*0a6a1f1dSLionel Sambuc 	NULL,
800*0a6a1f1dSLionel Sambuc 	addrport_print_addr,
801*0a6a1f1dSLionel Sambuc 	NULL,
802*0a6a1f1dSLionel Sambuc 	NULL,
803*0a6a1f1dSLionel Sambuc 	NULL,
804*0a6a1f1dSLionel Sambuc 	NULL
805*0a6a1f1dSLionel Sambuc     }
806ebfedea0SLionel Sambuc };
807ebfedea0SLionel Sambuc 
808ebfedea0SLionel Sambuc static int num_addrs = sizeof(at) / sizeof(at[0]);
809ebfedea0SLionel Sambuc 
810ebfedea0SLionel Sambuc static size_t max_sockaddr_size = 0;
811ebfedea0SLionel Sambuc 
812ebfedea0SLionel Sambuc /*
813ebfedea0SLionel Sambuc  * generic functions
814ebfedea0SLionel Sambuc  */
815ebfedea0SLionel Sambuc 
816ebfedea0SLionel Sambuc static struct addr_operations *
find_af(int af)817ebfedea0SLionel Sambuc find_af(int af)
818ebfedea0SLionel Sambuc {
819ebfedea0SLionel Sambuc     struct addr_operations *a;
820ebfedea0SLionel Sambuc 
821ebfedea0SLionel Sambuc     for (a = at; a < at + num_addrs; ++a)
822ebfedea0SLionel Sambuc 	if (af == a->af)
823ebfedea0SLionel Sambuc 	    return a;
824ebfedea0SLionel Sambuc     return NULL;
825ebfedea0SLionel Sambuc }
826ebfedea0SLionel Sambuc 
827ebfedea0SLionel Sambuc static struct addr_operations *
find_atype(krb5_address_type atype)828*0a6a1f1dSLionel Sambuc find_atype(krb5_address_type atype)
829ebfedea0SLionel Sambuc {
830ebfedea0SLionel Sambuc     struct addr_operations *a;
831ebfedea0SLionel Sambuc 
832ebfedea0SLionel Sambuc     for (a = at; a < at + num_addrs; ++a)
833ebfedea0SLionel Sambuc 	if (atype == a->atype)
834ebfedea0SLionel Sambuc 	    return a;
835ebfedea0SLionel Sambuc     return NULL;
836ebfedea0SLionel Sambuc }
837ebfedea0SLionel Sambuc 
838ebfedea0SLionel Sambuc /**
839ebfedea0SLionel Sambuc  * krb5_sockaddr2address stores a address a "struct sockaddr" sa in
840ebfedea0SLionel Sambuc  * the krb5_address addr.
841ebfedea0SLionel Sambuc  *
842ebfedea0SLionel Sambuc  * @param context a Keberos context
843ebfedea0SLionel Sambuc  * @param sa a struct sockaddr to extract the address from
844ebfedea0SLionel Sambuc  * @param addr an Kerberos 5 address to store the address in.
845ebfedea0SLionel Sambuc  *
846ebfedea0SLionel Sambuc  * @return Return an error code or 0.
847ebfedea0SLionel Sambuc  *
848ebfedea0SLionel Sambuc  * @ingroup krb5_address
849ebfedea0SLionel Sambuc  */
850ebfedea0SLionel Sambuc 
851ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_sockaddr2address(krb5_context context,const struct sockaddr * sa,krb5_address * addr)852ebfedea0SLionel Sambuc krb5_sockaddr2address (krb5_context context,
853ebfedea0SLionel Sambuc 		       const struct sockaddr *sa, krb5_address *addr)
854ebfedea0SLionel Sambuc {
855ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(sa->sa_family);
856ebfedea0SLionel Sambuc     if (a == NULL) {
857ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
858ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""),
859ebfedea0SLionel Sambuc 				sa->sa_family);
860ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
861ebfedea0SLionel Sambuc     }
862ebfedea0SLionel Sambuc     return (*a->sockaddr2addr)(sa, addr);
863ebfedea0SLionel Sambuc }
864ebfedea0SLionel Sambuc 
865ebfedea0SLionel Sambuc /**
866ebfedea0SLionel Sambuc  * krb5_sockaddr2port extracts a port (if possible) from a "struct
867ebfedea0SLionel Sambuc  * sockaddr.
868ebfedea0SLionel Sambuc  *
869ebfedea0SLionel Sambuc  * @param context a Keberos context
870ebfedea0SLionel Sambuc  * @param sa a struct sockaddr to extract the port from
871ebfedea0SLionel Sambuc  * @param port a pointer to an int16_t store the port in.
872ebfedea0SLionel Sambuc  *
873ebfedea0SLionel Sambuc  * @return Return an error code or 0. Will return
874ebfedea0SLionel Sambuc  * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
875ebfedea0SLionel Sambuc  *
876ebfedea0SLionel Sambuc  * @ingroup krb5_address
877ebfedea0SLionel Sambuc  */
878ebfedea0SLionel Sambuc 
879ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_sockaddr2port(krb5_context context,const struct sockaddr * sa,int16_t * port)880ebfedea0SLionel Sambuc krb5_sockaddr2port (krb5_context context,
881ebfedea0SLionel Sambuc 		    const struct sockaddr *sa, int16_t *port)
882ebfedea0SLionel Sambuc {
883ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(sa->sa_family);
884ebfedea0SLionel Sambuc     if (a == NULL) {
885ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
886ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""),
887ebfedea0SLionel Sambuc 				sa->sa_family);
888ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
889ebfedea0SLionel Sambuc     }
890ebfedea0SLionel Sambuc     return (*a->sockaddr2port)(sa, port);
891ebfedea0SLionel Sambuc }
892ebfedea0SLionel Sambuc 
893ebfedea0SLionel Sambuc /**
894ebfedea0SLionel Sambuc  * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr
895ebfedea0SLionel Sambuc  * and port. The argument sa_size should initially contain the size of
896ebfedea0SLionel Sambuc  * the sa and after the call, it will contain the actual length of the
897ebfedea0SLionel Sambuc  * address. In case of the sa is too small to fit the whole address,
898ebfedea0SLionel Sambuc  * the up to *sa_size will be stored, and then *sa_size will be set to
899ebfedea0SLionel Sambuc  * the required length.
900ebfedea0SLionel Sambuc  *
901ebfedea0SLionel Sambuc  * @param context a Keberos context
902ebfedea0SLionel Sambuc  * @param addr the address to copy the from
903ebfedea0SLionel Sambuc  * @param sa the struct sockaddr that will be filled in
904ebfedea0SLionel Sambuc  * @param sa_size pointer to length of sa, and after the call, it will
905ebfedea0SLionel Sambuc  * contain the actual length of the address.
906ebfedea0SLionel Sambuc  * @param port set port in sa.
907ebfedea0SLionel Sambuc  *
908ebfedea0SLionel Sambuc  * @return Return an error code or 0. Will return
909ebfedea0SLionel Sambuc  * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
910ebfedea0SLionel Sambuc  *
911ebfedea0SLionel Sambuc  * @ingroup krb5_address
912ebfedea0SLionel Sambuc  */
913ebfedea0SLionel Sambuc 
914ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_addr2sockaddr(krb5_context context,const krb5_address * addr,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)915ebfedea0SLionel Sambuc krb5_addr2sockaddr (krb5_context context,
916ebfedea0SLionel Sambuc 		    const krb5_address *addr,
917ebfedea0SLionel Sambuc 		    struct sockaddr *sa,
918ebfedea0SLionel Sambuc 		    krb5_socklen_t *sa_size,
919ebfedea0SLionel Sambuc 		    int port)
920ebfedea0SLionel Sambuc {
921ebfedea0SLionel Sambuc     struct addr_operations *a = find_atype(addr->addr_type);
922ebfedea0SLionel Sambuc 
923ebfedea0SLionel Sambuc     if (a == NULL) {
924ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
925ebfedea0SLionel Sambuc 				N_("Address type %d not supported",
926ebfedea0SLionel Sambuc 				   "krb5_address type"),
927ebfedea0SLionel Sambuc 				addr->addr_type);
928ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
929ebfedea0SLionel Sambuc     }
930ebfedea0SLionel Sambuc     if (a->addr2sockaddr == NULL) {
931ebfedea0SLionel Sambuc 	krb5_set_error_message (context,
932ebfedea0SLionel Sambuc 				KRB5_PROG_ATYPE_NOSUPP,
933ebfedea0SLionel Sambuc 				N_("Can't convert address type %d to sockaddr", ""),
934ebfedea0SLionel Sambuc 				addr->addr_type);
935ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
936ebfedea0SLionel Sambuc     }
937ebfedea0SLionel Sambuc     (*a->addr2sockaddr)(addr, sa, sa_size, port);
938ebfedea0SLionel Sambuc     return 0;
939ebfedea0SLionel Sambuc }
940ebfedea0SLionel Sambuc 
941ebfedea0SLionel Sambuc /**
942ebfedea0SLionel Sambuc  * krb5_max_sockaddr_size returns the max size of the .Li struct
943ebfedea0SLionel Sambuc  * sockaddr that the Kerberos library will return.
944ebfedea0SLionel Sambuc  *
945ebfedea0SLionel Sambuc  * @return Return an size_t of the maximum struct sockaddr.
946ebfedea0SLionel Sambuc  *
947ebfedea0SLionel Sambuc  * @ingroup krb5_address
948ebfedea0SLionel Sambuc  */
949ebfedea0SLionel Sambuc 
950ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
krb5_max_sockaddr_size(void)951ebfedea0SLionel Sambuc krb5_max_sockaddr_size (void)
952ebfedea0SLionel Sambuc {
953ebfedea0SLionel Sambuc     if (max_sockaddr_size == 0) {
954ebfedea0SLionel Sambuc 	struct addr_operations *a;
955ebfedea0SLionel Sambuc 
956ebfedea0SLionel Sambuc 	for(a = at; a < at + num_addrs; ++a)
957ebfedea0SLionel Sambuc 	    max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size);
958ebfedea0SLionel Sambuc     }
959ebfedea0SLionel Sambuc     return max_sockaddr_size;
960ebfedea0SLionel Sambuc }
961ebfedea0SLionel Sambuc 
962ebfedea0SLionel Sambuc /**
963ebfedea0SLionel Sambuc  * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the
964ebfedea0SLionel Sambuc  * kerberos library thinks are uninteresting.  One example are link
965ebfedea0SLionel Sambuc  * local addresses.
966ebfedea0SLionel Sambuc  *
967ebfedea0SLionel Sambuc  * @param sa pointer to struct sockaddr that might be interesting.
968ebfedea0SLionel Sambuc  *
969ebfedea0SLionel Sambuc  * @return Return a non zero for uninteresting addresses.
970ebfedea0SLionel Sambuc  *
971ebfedea0SLionel Sambuc  * @ingroup krb5_address
972ebfedea0SLionel Sambuc  */
973ebfedea0SLionel Sambuc 
974ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_sockaddr_uninteresting(const struct sockaddr * sa)975ebfedea0SLionel Sambuc krb5_sockaddr_uninteresting(const struct sockaddr *sa)
976ebfedea0SLionel Sambuc {
977ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(sa->sa_family);
978ebfedea0SLionel Sambuc     if (a == NULL || a->uninteresting == NULL)
979ebfedea0SLionel Sambuc 	return TRUE;
980ebfedea0SLionel Sambuc     return (*a->uninteresting)(sa);
981ebfedea0SLionel Sambuc }
982ebfedea0SLionel Sambuc 
983ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_sockaddr_is_loopback(const struct sockaddr * sa)984ebfedea0SLionel Sambuc krb5_sockaddr_is_loopback(const struct sockaddr *sa)
985ebfedea0SLionel Sambuc {
986ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(sa->sa_family);
987ebfedea0SLionel Sambuc     if (a == NULL || a->is_loopback == NULL)
988ebfedea0SLionel Sambuc 	return TRUE;
989ebfedea0SLionel Sambuc     return (*a->is_loopback)(sa);
990ebfedea0SLionel Sambuc }
991ebfedea0SLionel Sambuc 
992ebfedea0SLionel Sambuc /**
993ebfedea0SLionel Sambuc  * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and
994ebfedea0SLionel Sambuc  * the "struct hostent" (see gethostbyname(3) ) h_addr_list
995ebfedea0SLionel Sambuc  * component. The argument sa_size should initially contain the size
996ebfedea0SLionel Sambuc  * of the sa, and after the call, it will contain the actual length of
997ebfedea0SLionel Sambuc  * the address.
998ebfedea0SLionel Sambuc  *
999ebfedea0SLionel Sambuc  * @param context a Keberos context
1000ebfedea0SLionel Sambuc  * @param af addresses
1001ebfedea0SLionel Sambuc  * @param addr address
1002ebfedea0SLionel Sambuc  * @param sa returned struct sockaddr
1003ebfedea0SLionel Sambuc  * @param sa_size size of sa
1004ebfedea0SLionel Sambuc  * @param port port to set in sa.
1005ebfedea0SLionel Sambuc  *
1006ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1007ebfedea0SLionel Sambuc  *
1008ebfedea0SLionel Sambuc  * @ingroup krb5_address
1009ebfedea0SLionel Sambuc  */
1010ebfedea0SLionel Sambuc 
1011ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_h_addr2sockaddr(krb5_context context,int af,const char * addr,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)1012ebfedea0SLionel Sambuc krb5_h_addr2sockaddr (krb5_context context,
1013ebfedea0SLionel Sambuc 		      int af,
1014ebfedea0SLionel Sambuc 		      const char *addr, struct sockaddr *sa,
1015ebfedea0SLionel Sambuc 		      krb5_socklen_t *sa_size,
1016ebfedea0SLionel Sambuc 		      int port)
1017ebfedea0SLionel Sambuc {
1018ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(af);
1019ebfedea0SLionel Sambuc     if (a == NULL) {
1020ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1021ebfedea0SLionel Sambuc 				"Address family %d not supported", af);
1022ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
1023ebfedea0SLionel Sambuc     }
1024ebfedea0SLionel Sambuc     (*a->h_addr2sockaddr)(addr, sa, sa_size, port);
1025ebfedea0SLionel Sambuc     return 0;
1026ebfedea0SLionel Sambuc }
1027ebfedea0SLionel Sambuc 
1028ebfedea0SLionel Sambuc /**
1029ebfedea0SLionel Sambuc  * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception
1030ebfedea0SLionel Sambuc  * that it operates on a krb5_address instead of a struct sockaddr.
1031ebfedea0SLionel Sambuc  *
1032ebfedea0SLionel Sambuc  * @param context a Keberos context
1033ebfedea0SLionel Sambuc  * @param af address family
1034ebfedea0SLionel Sambuc  * @param haddr host address from struct hostent.
1035ebfedea0SLionel Sambuc  * @param addr returned krb5_address.
1036ebfedea0SLionel Sambuc  *
1037ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1038ebfedea0SLionel Sambuc  *
1039ebfedea0SLionel Sambuc  * @ingroup krb5_address
1040ebfedea0SLionel Sambuc  */
1041ebfedea0SLionel Sambuc 
1042ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_h_addr2addr(krb5_context context,int af,const char * haddr,krb5_address * addr)1043ebfedea0SLionel Sambuc krb5_h_addr2addr (krb5_context context,
1044ebfedea0SLionel Sambuc 		  int af,
1045ebfedea0SLionel Sambuc 		  const char *haddr, krb5_address *addr)
1046ebfedea0SLionel Sambuc {
1047ebfedea0SLionel Sambuc     struct addr_operations *a = find_af(af);
1048ebfedea0SLionel Sambuc     if (a == NULL) {
1049ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1050ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""), af);
1051ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
1052ebfedea0SLionel Sambuc     }
1053ebfedea0SLionel Sambuc     return (*a->h_addr2addr)(haddr, addr);
1054ebfedea0SLionel Sambuc }
1055ebfedea0SLionel Sambuc 
1056ebfedea0SLionel Sambuc /**
1057ebfedea0SLionel Sambuc  * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to
1058ebfedea0SLionel Sambuc  * bind(2) to.  The argument sa_size should initially contain the size
1059ebfedea0SLionel Sambuc  * of the sa, and after the call, it will contain the actual length
1060ebfedea0SLionel Sambuc  * of the address.
1061ebfedea0SLionel Sambuc  *
1062ebfedea0SLionel Sambuc  * @param context a Keberos context
1063ebfedea0SLionel Sambuc  * @param af address family
1064ebfedea0SLionel Sambuc  * @param sa sockaddr
1065ebfedea0SLionel Sambuc  * @param sa_size lenght of sa.
1066ebfedea0SLionel Sambuc  * @param port for to fill into sa.
1067ebfedea0SLionel Sambuc  *
1068ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1069ebfedea0SLionel Sambuc  *
1070ebfedea0SLionel Sambuc  * @ingroup krb5_address
1071ebfedea0SLionel Sambuc  */
1072ebfedea0SLionel Sambuc 
1073ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_anyaddr(krb5_context context,int af,struct sockaddr * sa,krb5_socklen_t * sa_size,int port)1074ebfedea0SLionel Sambuc krb5_anyaddr (krb5_context context,
1075ebfedea0SLionel Sambuc 	      int af,
1076ebfedea0SLionel Sambuc 	      struct sockaddr *sa,
1077ebfedea0SLionel Sambuc 	      krb5_socklen_t *sa_size,
1078ebfedea0SLionel Sambuc 	      int port)
1079ebfedea0SLionel Sambuc {
1080ebfedea0SLionel Sambuc     struct addr_operations *a = find_af (af);
1081ebfedea0SLionel Sambuc 
1082ebfedea0SLionel Sambuc     if (a == NULL) {
1083ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1084ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""), af);
1085ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
1086ebfedea0SLionel Sambuc     }
1087ebfedea0SLionel Sambuc 
1088ebfedea0SLionel Sambuc     (*a->anyaddr)(sa, sa_size, port);
1089ebfedea0SLionel Sambuc     return 0;
1090ebfedea0SLionel Sambuc }
1091ebfedea0SLionel Sambuc 
1092ebfedea0SLionel Sambuc /**
1093ebfedea0SLionel Sambuc  * krb5_print_address prints the address in addr to the string string
1094ebfedea0SLionel Sambuc  * that have the length len. If ret_len is not NULL, it will be filled
1095ebfedea0SLionel Sambuc  * with the length of the string if size were unlimited (not including
1096ebfedea0SLionel Sambuc  * the final NUL) .
1097ebfedea0SLionel Sambuc  *
1098ebfedea0SLionel Sambuc  * @param addr address to be printed
1099ebfedea0SLionel Sambuc  * @param str pointer string to print the address into
1100ebfedea0SLionel Sambuc  * @param len length that will fit into area pointed to by "str".
1101ebfedea0SLionel Sambuc  * @param ret_len return length the str.
1102ebfedea0SLionel Sambuc  *
1103ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1104ebfedea0SLionel Sambuc  *
1105ebfedea0SLionel Sambuc  * @ingroup krb5_address
1106ebfedea0SLionel Sambuc  */
1107ebfedea0SLionel Sambuc 
1108ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_print_address(const krb5_address * addr,char * str,size_t len,size_t * ret_len)1109ebfedea0SLionel Sambuc krb5_print_address (const krb5_address *addr,
1110ebfedea0SLionel Sambuc 		    char *str, size_t len, size_t *ret_len)
1111ebfedea0SLionel Sambuc {
1112ebfedea0SLionel Sambuc     struct addr_operations *a = find_atype(addr->addr_type);
1113ebfedea0SLionel Sambuc     int ret;
1114ebfedea0SLionel Sambuc 
1115ebfedea0SLionel Sambuc     if (a == NULL || a->print_addr == NULL) {
1116ebfedea0SLionel Sambuc 	char *s;
1117ebfedea0SLionel Sambuc 	int l;
1118*0a6a1f1dSLionel Sambuc 	size_t i;
1119ebfedea0SLionel Sambuc 
1120ebfedea0SLionel Sambuc 	s = str;
1121ebfedea0SLionel Sambuc 	l = snprintf(s, len, "TYPE_%d:", addr->addr_type);
1122*0a6a1f1dSLionel Sambuc 	if (l < 0 || (size_t)l >= len)
1123ebfedea0SLionel Sambuc 	    return EINVAL;
1124ebfedea0SLionel Sambuc 	s += l;
1125ebfedea0SLionel Sambuc 	len -= l;
1126ebfedea0SLionel Sambuc 	for(i = 0; i < addr->address.length; i++) {
1127ebfedea0SLionel Sambuc 	    l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]);
1128*0a6a1f1dSLionel Sambuc 	    if (l < 0 || (size_t)l >= len)
1129ebfedea0SLionel Sambuc 		return EINVAL;
1130ebfedea0SLionel Sambuc 	    len -= l;
1131ebfedea0SLionel Sambuc 	    s += l;
1132ebfedea0SLionel Sambuc 	}
1133ebfedea0SLionel Sambuc 	if(ret_len != NULL)
1134ebfedea0SLionel Sambuc 	    *ret_len = s - str;
1135ebfedea0SLionel Sambuc 	return 0;
1136ebfedea0SLionel Sambuc     }
1137ebfedea0SLionel Sambuc     ret = (*a->print_addr)(addr, str, len);
1138ebfedea0SLionel Sambuc     if (ret < 0)
1139ebfedea0SLionel Sambuc 	return EINVAL;
1140ebfedea0SLionel Sambuc     if(ret_len != NULL)
1141ebfedea0SLionel Sambuc 	*ret_len = ret;
1142ebfedea0SLionel Sambuc     return 0;
1143ebfedea0SLionel Sambuc }
1144ebfedea0SLionel Sambuc 
1145ebfedea0SLionel Sambuc /**
1146ebfedea0SLionel Sambuc  * krb5_parse_address returns the resolved hostname in string to the
1147ebfedea0SLionel Sambuc  * krb5_addresses addresses .
1148ebfedea0SLionel Sambuc  *
1149ebfedea0SLionel Sambuc  * @param context a Keberos context
1150ebfedea0SLionel Sambuc  * @param string
1151ebfedea0SLionel Sambuc  * @param addresses
1152ebfedea0SLionel Sambuc  *
1153ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1154ebfedea0SLionel Sambuc  *
1155ebfedea0SLionel Sambuc  * @ingroup krb5_address
1156ebfedea0SLionel Sambuc  */
1157ebfedea0SLionel Sambuc 
1158ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_parse_address(krb5_context context,const char * string,krb5_addresses * addresses)1159ebfedea0SLionel Sambuc krb5_parse_address(krb5_context context,
1160ebfedea0SLionel Sambuc 		   const char *string,
1161ebfedea0SLionel Sambuc 		   krb5_addresses *addresses)
1162ebfedea0SLionel Sambuc {
1163ebfedea0SLionel Sambuc     int i, n;
1164ebfedea0SLionel Sambuc     struct addrinfo *ai, *a;
1165ebfedea0SLionel Sambuc     int error;
1166ebfedea0SLionel Sambuc     int save_errno;
1167ebfedea0SLionel Sambuc 
1168ebfedea0SLionel Sambuc     addresses->len = 0;
1169ebfedea0SLionel Sambuc     addresses->val = NULL;
1170ebfedea0SLionel Sambuc 
1171ebfedea0SLionel Sambuc     for(i = 0; i < num_addrs; i++) {
1172ebfedea0SLionel Sambuc 	if(at[i].parse_addr) {
1173ebfedea0SLionel Sambuc 	    krb5_address addr;
1174ebfedea0SLionel Sambuc 	    if((*at[i].parse_addr)(context, string, &addr) == 0) {
1175ebfedea0SLionel Sambuc 		ALLOC_SEQ(addresses, 1);
1176ebfedea0SLionel Sambuc 		if (addresses->val == NULL) {
1177ebfedea0SLionel Sambuc 		    krb5_set_error_message(context, ENOMEM,
1178ebfedea0SLionel Sambuc 					   N_("malloc: out of memory", ""));
1179ebfedea0SLionel Sambuc 		    return ENOMEM;
1180ebfedea0SLionel Sambuc 		}
1181ebfedea0SLionel Sambuc 		addresses->val[0] = addr;
1182ebfedea0SLionel Sambuc 		return 0;
1183ebfedea0SLionel Sambuc 	    }
1184ebfedea0SLionel Sambuc 	}
1185ebfedea0SLionel Sambuc     }
1186ebfedea0SLionel Sambuc 
1187ebfedea0SLionel Sambuc     error = getaddrinfo (string, NULL, NULL, &ai);
1188ebfedea0SLionel Sambuc     if (error) {
1189ebfedea0SLionel Sambuc 	krb5_error_code ret2;
1190ebfedea0SLionel Sambuc 	save_errno = errno;
1191ebfedea0SLionel Sambuc 	ret2 = krb5_eai_to_heim_errno(error, save_errno);
1192ebfedea0SLionel Sambuc 	krb5_set_error_message (context, ret2, "%s: %s",
1193ebfedea0SLionel Sambuc 				string, gai_strerror(error));
1194ebfedea0SLionel Sambuc 	return ret2;
1195ebfedea0SLionel Sambuc     }
1196ebfedea0SLionel Sambuc 
1197ebfedea0SLionel Sambuc     n = 0;
1198ebfedea0SLionel Sambuc     for (a = ai; a != NULL; a = a->ai_next)
1199ebfedea0SLionel Sambuc 	++n;
1200ebfedea0SLionel Sambuc 
1201ebfedea0SLionel Sambuc     ALLOC_SEQ(addresses, n);
1202ebfedea0SLionel Sambuc     if (addresses->val == NULL) {
1203ebfedea0SLionel Sambuc 	krb5_set_error_message(context, ENOMEM,
1204ebfedea0SLionel Sambuc 			       N_("malloc: out of memory", ""));
1205ebfedea0SLionel Sambuc 	freeaddrinfo(ai);
1206ebfedea0SLionel Sambuc 	return ENOMEM;
1207ebfedea0SLionel Sambuc     }
1208ebfedea0SLionel Sambuc 
1209ebfedea0SLionel Sambuc     addresses->len = 0;
1210ebfedea0SLionel Sambuc     for (a = ai, i = 0; a != NULL; a = a->ai_next) {
1211*0a6a1f1dSLionel Sambuc 	if (krb5_sockaddr2address (context, a->ai_addr, &addresses->val[i]))
1212ebfedea0SLionel Sambuc 	    continue;
1213ebfedea0SLionel Sambuc 	if(krb5_address_search(context, &addresses->val[i], addresses)) {
1214ebfedea0SLionel Sambuc 	    krb5_free_address(context, &addresses->val[i]);
1215ebfedea0SLionel Sambuc 	    continue;
1216ebfedea0SLionel Sambuc 	}
1217ebfedea0SLionel Sambuc 	i++;
1218ebfedea0SLionel Sambuc 	addresses->len = i;
1219ebfedea0SLionel Sambuc     }
1220ebfedea0SLionel Sambuc     freeaddrinfo (ai);
1221ebfedea0SLionel Sambuc     return 0;
1222ebfedea0SLionel Sambuc }
1223ebfedea0SLionel Sambuc 
1224ebfedea0SLionel Sambuc /**
1225ebfedea0SLionel Sambuc  * krb5_address_order compares the addresses addr1 and addr2 so that
1226ebfedea0SLionel Sambuc  * it can be used for sorting addresses. If the addresses are the same
1227ebfedea0SLionel Sambuc  * address krb5_address_order will return 0. Behavies like memcmp(2).
1228ebfedea0SLionel Sambuc  *
1229ebfedea0SLionel Sambuc  * @param context a Keberos context
1230ebfedea0SLionel Sambuc  * @param addr1 krb5_address to compare
1231ebfedea0SLionel Sambuc  * @param addr2 krb5_address to compare
1232ebfedea0SLionel Sambuc  *
1233ebfedea0SLionel Sambuc  * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and
1234ebfedea0SLionel Sambuc  * addr2 is the same address, > 0 if addr2 is "less" then addr1.
1235ebfedea0SLionel Sambuc  *
1236ebfedea0SLionel Sambuc  * @ingroup krb5_address
1237ebfedea0SLionel Sambuc  */
1238ebfedea0SLionel Sambuc 
1239ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION int KRB5_LIB_CALL
krb5_address_order(krb5_context context,const krb5_address * addr1,const krb5_address * addr2)1240ebfedea0SLionel Sambuc krb5_address_order(krb5_context context,
1241ebfedea0SLionel Sambuc 		   const krb5_address *addr1,
1242ebfedea0SLionel Sambuc 		   const krb5_address *addr2)
1243ebfedea0SLionel Sambuc {
1244ebfedea0SLionel Sambuc     /* this sucks; what if both addresses have order functions, which
1245ebfedea0SLionel Sambuc        should we call? this works for now, though */
1246ebfedea0SLionel Sambuc     struct addr_operations *a;
1247ebfedea0SLionel Sambuc     a = find_atype(addr1->addr_type);
1248ebfedea0SLionel Sambuc     if(a == NULL) {
1249ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1250ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""),
1251ebfedea0SLionel Sambuc 				addr1->addr_type);
1252ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
1253ebfedea0SLionel Sambuc     }
1254ebfedea0SLionel Sambuc     if(a->order_addr != NULL)
1255ebfedea0SLionel Sambuc 	return (*a->order_addr)(context, addr1, addr2);
1256ebfedea0SLionel Sambuc     a = find_atype(addr2->addr_type);
1257ebfedea0SLionel Sambuc     if(a == NULL) {
1258ebfedea0SLionel Sambuc 	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1259ebfedea0SLionel Sambuc 				N_("Address family %d not supported", ""),
1260ebfedea0SLionel Sambuc 				addr2->addr_type);
1261ebfedea0SLionel Sambuc 	return KRB5_PROG_ATYPE_NOSUPP;
1262ebfedea0SLionel Sambuc     }
1263ebfedea0SLionel Sambuc     if(a->order_addr != NULL)
1264ebfedea0SLionel Sambuc 	return (*a->order_addr)(context, addr1, addr2);
1265ebfedea0SLionel Sambuc 
1266ebfedea0SLionel Sambuc     if(addr1->addr_type != addr2->addr_type)
1267ebfedea0SLionel Sambuc 	return addr1->addr_type - addr2->addr_type;
1268ebfedea0SLionel Sambuc     if(addr1->address.length != addr2->address.length)
1269ebfedea0SLionel Sambuc 	return addr1->address.length - addr2->address.length;
1270ebfedea0SLionel Sambuc     return memcmp (addr1->address.data,
1271ebfedea0SLionel Sambuc 		   addr2->address.data,
1272ebfedea0SLionel Sambuc 		   addr1->address.length);
1273ebfedea0SLionel Sambuc }
1274ebfedea0SLionel Sambuc 
1275ebfedea0SLionel Sambuc /**
1276ebfedea0SLionel Sambuc  * krb5_address_compare compares the addresses  addr1 and addr2.
1277ebfedea0SLionel Sambuc  * Returns TRUE if the two addresses are the same.
1278ebfedea0SLionel Sambuc  *
1279ebfedea0SLionel Sambuc  * @param context a Keberos context
1280ebfedea0SLionel Sambuc  * @param addr1 address to compare
1281ebfedea0SLionel Sambuc  * @param addr2 address to compare
1282ebfedea0SLionel Sambuc  *
1283ebfedea0SLionel Sambuc  * @return Return an TRUE is the address are the same FALSE if not
1284ebfedea0SLionel Sambuc  *
1285ebfedea0SLionel Sambuc  * @ingroup krb5_address
1286ebfedea0SLionel Sambuc  */
1287ebfedea0SLionel Sambuc 
1288ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_address_compare(krb5_context context,const krb5_address * addr1,const krb5_address * addr2)1289ebfedea0SLionel Sambuc krb5_address_compare(krb5_context context,
1290ebfedea0SLionel Sambuc 		     const krb5_address *addr1,
1291ebfedea0SLionel Sambuc 		     const krb5_address *addr2)
1292ebfedea0SLionel Sambuc {
1293ebfedea0SLionel Sambuc     return krb5_address_order (context, addr1, addr2) == 0;
1294ebfedea0SLionel Sambuc }
1295ebfedea0SLionel Sambuc 
1296ebfedea0SLionel Sambuc /**
1297ebfedea0SLionel Sambuc  * krb5_address_search checks if the address addr is a member of the
1298ebfedea0SLionel Sambuc  * address set list addrlist .
1299ebfedea0SLionel Sambuc  *
1300ebfedea0SLionel Sambuc  * @param context a Keberos context.
1301ebfedea0SLionel Sambuc  * @param addr address to search for.
1302ebfedea0SLionel Sambuc  * @param addrlist list of addresses to look in for addr.
1303ebfedea0SLionel Sambuc  *
1304ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1305ebfedea0SLionel Sambuc  *
1306ebfedea0SLionel Sambuc  * @ingroup krb5_address
1307ebfedea0SLionel Sambuc  */
1308ebfedea0SLionel Sambuc 
1309ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
krb5_address_search(krb5_context context,const krb5_address * addr,const krb5_addresses * addrlist)1310ebfedea0SLionel Sambuc krb5_address_search(krb5_context context,
1311ebfedea0SLionel Sambuc 		    const krb5_address *addr,
1312ebfedea0SLionel Sambuc 		    const krb5_addresses *addrlist)
1313ebfedea0SLionel Sambuc {
1314*0a6a1f1dSLionel Sambuc     size_t i;
1315ebfedea0SLionel Sambuc 
1316ebfedea0SLionel Sambuc     for (i = 0; i < addrlist->len; ++i)
1317ebfedea0SLionel Sambuc 	if (krb5_address_compare (context, addr, &addrlist->val[i]))
1318ebfedea0SLionel Sambuc 	    return TRUE;
1319ebfedea0SLionel Sambuc     return FALSE;
1320ebfedea0SLionel Sambuc }
1321ebfedea0SLionel Sambuc 
1322ebfedea0SLionel Sambuc /**
1323ebfedea0SLionel Sambuc  * krb5_free_address frees the data stored in the address that is
1324ebfedea0SLionel Sambuc  * alloced with any of the krb5_address functions.
1325ebfedea0SLionel Sambuc  *
1326ebfedea0SLionel Sambuc  * @param context a Keberos context
1327ebfedea0SLionel Sambuc  * @param address addresss to be freed.
1328ebfedea0SLionel Sambuc  *
1329ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1330ebfedea0SLionel Sambuc  *
1331ebfedea0SLionel Sambuc  * @ingroup krb5_address
1332ebfedea0SLionel Sambuc  */
1333ebfedea0SLionel Sambuc 
1334ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_free_address(krb5_context context,krb5_address * address)1335ebfedea0SLionel Sambuc krb5_free_address(krb5_context context,
1336ebfedea0SLionel Sambuc 		  krb5_address *address)
1337ebfedea0SLionel Sambuc {
1338ebfedea0SLionel Sambuc     struct addr_operations *a = find_atype (address->addr_type);
1339ebfedea0SLionel Sambuc     if(a != NULL && a->free_addr != NULL)
1340ebfedea0SLionel Sambuc 	return (*a->free_addr)(context, address);
1341ebfedea0SLionel Sambuc     krb5_data_free (&address->address);
1342ebfedea0SLionel Sambuc     memset(address, 0, sizeof(*address));
1343ebfedea0SLionel Sambuc     return 0;
1344ebfedea0SLionel Sambuc }
1345ebfedea0SLionel Sambuc 
1346ebfedea0SLionel Sambuc /**
1347ebfedea0SLionel Sambuc  * krb5_free_addresses frees the data stored in the address that is
1348ebfedea0SLionel Sambuc  * alloced with any of the krb5_address functions.
1349ebfedea0SLionel Sambuc  *
1350ebfedea0SLionel Sambuc  * @param context a Keberos context
1351ebfedea0SLionel Sambuc  * @param addresses addressses to be freed.
1352ebfedea0SLionel Sambuc  *
1353ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1354ebfedea0SLionel Sambuc  *
1355ebfedea0SLionel Sambuc  * @ingroup krb5_address
1356ebfedea0SLionel Sambuc  */
1357ebfedea0SLionel Sambuc 
1358ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_free_addresses(krb5_context context,krb5_addresses * addresses)1359ebfedea0SLionel Sambuc krb5_free_addresses(krb5_context context,
1360ebfedea0SLionel Sambuc 		    krb5_addresses *addresses)
1361ebfedea0SLionel Sambuc {
1362*0a6a1f1dSLionel Sambuc     size_t i;
1363ebfedea0SLionel Sambuc     for(i = 0; i < addresses->len; i++)
1364ebfedea0SLionel Sambuc 	krb5_free_address(context, &addresses->val[i]);
1365ebfedea0SLionel Sambuc     free(addresses->val);
1366ebfedea0SLionel Sambuc     addresses->len = 0;
1367ebfedea0SLionel Sambuc     addresses->val = NULL;
1368ebfedea0SLionel Sambuc     return 0;
1369ebfedea0SLionel Sambuc }
1370ebfedea0SLionel Sambuc 
1371ebfedea0SLionel Sambuc /**
1372ebfedea0SLionel Sambuc  * krb5_copy_address copies the content of address
1373ebfedea0SLionel Sambuc  * inaddr to outaddr.
1374ebfedea0SLionel Sambuc  *
1375ebfedea0SLionel Sambuc  * @param context a Keberos context
1376ebfedea0SLionel Sambuc  * @param inaddr pointer to source address
1377ebfedea0SLionel Sambuc  * @param outaddr pointer to destination address
1378ebfedea0SLionel Sambuc  *
1379ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1380ebfedea0SLionel Sambuc  *
1381ebfedea0SLionel Sambuc  * @ingroup krb5_address
1382ebfedea0SLionel Sambuc  */
1383ebfedea0SLionel Sambuc 
1384ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_copy_address(krb5_context context,const krb5_address * inaddr,krb5_address * outaddr)1385ebfedea0SLionel Sambuc krb5_copy_address(krb5_context context,
1386ebfedea0SLionel Sambuc 		  const krb5_address *inaddr,
1387ebfedea0SLionel Sambuc 		  krb5_address *outaddr)
1388ebfedea0SLionel Sambuc {
1389ebfedea0SLionel Sambuc     struct addr_operations *a = find_af (inaddr->addr_type);
1390ebfedea0SLionel Sambuc     if(a != NULL && a->copy_addr != NULL)
1391ebfedea0SLionel Sambuc 	return (*a->copy_addr)(context, inaddr, outaddr);
1392ebfedea0SLionel Sambuc     return copy_HostAddress(inaddr, outaddr);
1393ebfedea0SLionel Sambuc }
1394ebfedea0SLionel Sambuc 
1395ebfedea0SLionel Sambuc /**
1396ebfedea0SLionel Sambuc  * krb5_copy_addresses copies the content of addresses
1397ebfedea0SLionel Sambuc  * inaddr to outaddr.
1398ebfedea0SLionel Sambuc  *
1399ebfedea0SLionel Sambuc  * @param context a Keberos context
1400ebfedea0SLionel Sambuc  * @param inaddr pointer to source addresses
1401ebfedea0SLionel Sambuc  * @param outaddr pointer to destination addresses
1402ebfedea0SLionel Sambuc  *
1403ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1404ebfedea0SLionel Sambuc  *
1405ebfedea0SLionel Sambuc  * @ingroup krb5_address
1406ebfedea0SLionel Sambuc  */
1407ebfedea0SLionel Sambuc 
1408ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_copy_addresses(krb5_context context,const krb5_addresses * inaddr,krb5_addresses * outaddr)1409ebfedea0SLionel Sambuc krb5_copy_addresses(krb5_context context,
1410ebfedea0SLionel Sambuc 		    const krb5_addresses *inaddr,
1411ebfedea0SLionel Sambuc 		    krb5_addresses *outaddr)
1412ebfedea0SLionel Sambuc {
1413*0a6a1f1dSLionel Sambuc     size_t i;
1414ebfedea0SLionel Sambuc     ALLOC_SEQ(outaddr, inaddr->len);
1415ebfedea0SLionel Sambuc     if(inaddr->len > 0 && outaddr->val == NULL)
1416ebfedea0SLionel Sambuc 	return ENOMEM;
1417ebfedea0SLionel Sambuc     for(i = 0; i < inaddr->len; i++)
1418ebfedea0SLionel Sambuc 	krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]);
1419ebfedea0SLionel Sambuc     return 0;
1420ebfedea0SLionel Sambuc }
1421ebfedea0SLionel Sambuc 
1422ebfedea0SLionel Sambuc /**
1423ebfedea0SLionel Sambuc  * krb5_append_addresses adds the set of addresses in source to
1424ebfedea0SLionel Sambuc  * dest. While copying the addresses, duplicates are also sorted out.
1425ebfedea0SLionel Sambuc  *
1426ebfedea0SLionel Sambuc  * @param context a Keberos context
1427ebfedea0SLionel Sambuc  * @param dest destination of copy operation
1428ebfedea0SLionel Sambuc  * @param source adresses that are going to be added to dest
1429ebfedea0SLionel Sambuc  *
1430ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1431ebfedea0SLionel Sambuc  *
1432ebfedea0SLionel Sambuc  * @ingroup krb5_address
1433ebfedea0SLionel Sambuc  */
1434ebfedea0SLionel Sambuc 
1435ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_append_addresses(krb5_context context,krb5_addresses * dest,const krb5_addresses * source)1436ebfedea0SLionel Sambuc krb5_append_addresses(krb5_context context,
1437ebfedea0SLionel Sambuc 		      krb5_addresses *dest,
1438ebfedea0SLionel Sambuc 		      const krb5_addresses *source)
1439ebfedea0SLionel Sambuc {
1440ebfedea0SLionel Sambuc     krb5_address *tmp;
1441ebfedea0SLionel Sambuc     krb5_error_code ret;
1442*0a6a1f1dSLionel Sambuc     size_t i;
1443ebfedea0SLionel Sambuc     if(source->len > 0) {
1444ebfedea0SLionel Sambuc 	tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp));
1445ebfedea0SLionel Sambuc 	if(tmp == NULL) {
1446ebfedea0SLionel Sambuc 	    krb5_set_error_message (context, ENOMEM,
1447ebfedea0SLionel Sambuc 				    N_("malloc: out of memory", ""));
1448ebfedea0SLionel Sambuc 	    return ENOMEM;
1449ebfedea0SLionel Sambuc 	}
1450ebfedea0SLionel Sambuc 	dest->val = tmp;
1451ebfedea0SLionel Sambuc 	for(i = 0; i < source->len; i++) {
1452ebfedea0SLionel Sambuc 	    /* skip duplicates */
1453ebfedea0SLionel Sambuc 	    if(krb5_address_search(context, &source->val[i], dest))
1454ebfedea0SLionel Sambuc 		continue;
1455ebfedea0SLionel Sambuc 	    ret = krb5_copy_address(context,
1456ebfedea0SLionel Sambuc 				    &source->val[i],
1457ebfedea0SLionel Sambuc 				    &dest->val[dest->len]);
1458ebfedea0SLionel Sambuc 	    if(ret)
1459ebfedea0SLionel Sambuc 		return ret;
1460ebfedea0SLionel Sambuc 	    dest->len++;
1461ebfedea0SLionel Sambuc 	}
1462ebfedea0SLionel Sambuc     }
1463ebfedea0SLionel Sambuc     return 0;
1464ebfedea0SLionel Sambuc }
1465ebfedea0SLionel Sambuc 
1466ebfedea0SLionel Sambuc /**
1467ebfedea0SLionel Sambuc  * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
1468ebfedea0SLionel Sambuc  *
1469ebfedea0SLionel Sambuc  * @param context a Keberos context
1470ebfedea0SLionel Sambuc  * @param res built address from addr/port
1471ebfedea0SLionel Sambuc  * @param addr address to use
1472ebfedea0SLionel Sambuc  * @param port port to use
1473ebfedea0SLionel Sambuc  *
1474ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1475ebfedea0SLionel Sambuc  *
1476ebfedea0SLionel Sambuc  * @ingroup krb5_address
1477ebfedea0SLionel Sambuc  */
1478ebfedea0SLionel Sambuc 
1479ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_make_addrport(krb5_context context,krb5_address ** res,const krb5_address * addr,int16_t port)1480ebfedea0SLionel Sambuc krb5_make_addrport (krb5_context context,
1481ebfedea0SLionel Sambuc 		    krb5_address **res, const krb5_address *addr, int16_t port)
1482ebfedea0SLionel Sambuc {
1483ebfedea0SLionel Sambuc     krb5_error_code ret;
1484ebfedea0SLionel Sambuc     size_t len = addr->address.length + 2 + 4 * 4;
1485ebfedea0SLionel Sambuc     u_char *p;
1486ebfedea0SLionel Sambuc 
1487ebfedea0SLionel Sambuc     *res = malloc (sizeof(**res));
1488ebfedea0SLionel Sambuc     if (*res == NULL) {
1489ebfedea0SLionel Sambuc 	krb5_set_error_message (context, ENOMEM,
1490ebfedea0SLionel Sambuc 				N_("malloc: out of memory", ""));
1491ebfedea0SLionel Sambuc 	return ENOMEM;
1492ebfedea0SLionel Sambuc     }
1493ebfedea0SLionel Sambuc     (*res)->addr_type = KRB5_ADDRESS_ADDRPORT;
1494ebfedea0SLionel Sambuc     ret = krb5_data_alloc (&(*res)->address, len);
1495ebfedea0SLionel Sambuc     if (ret) {
1496ebfedea0SLionel Sambuc 	krb5_set_error_message (context, ret,
1497ebfedea0SLionel Sambuc 				N_("malloc: out of memory", ""));
1498ebfedea0SLionel Sambuc 	free (*res);
1499ebfedea0SLionel Sambuc 	*res = NULL;
1500ebfedea0SLionel Sambuc 	return ret;
1501ebfedea0SLionel Sambuc     }
1502ebfedea0SLionel Sambuc     p = (*res)->address.data;
1503ebfedea0SLionel Sambuc     *p++ = 0;
1504ebfedea0SLionel Sambuc     *p++ = 0;
1505ebfedea0SLionel Sambuc     *p++ = (addr->addr_type     ) & 0xFF;
1506ebfedea0SLionel Sambuc     *p++ = (addr->addr_type >> 8) & 0xFF;
1507ebfedea0SLionel Sambuc 
1508ebfedea0SLionel Sambuc     *p++ = (addr->address.length      ) & 0xFF;
1509ebfedea0SLionel Sambuc     *p++ = (addr->address.length >>  8) & 0xFF;
1510ebfedea0SLionel Sambuc     *p++ = (addr->address.length >> 16) & 0xFF;
1511ebfedea0SLionel Sambuc     *p++ = (addr->address.length >> 24) & 0xFF;
1512ebfedea0SLionel Sambuc 
1513ebfedea0SLionel Sambuc     memcpy (p, addr->address.data, addr->address.length);
1514ebfedea0SLionel Sambuc     p += addr->address.length;
1515ebfedea0SLionel Sambuc 
1516ebfedea0SLionel Sambuc     *p++ = 0;
1517ebfedea0SLionel Sambuc     *p++ = 0;
1518ebfedea0SLionel Sambuc     *p++ = (KRB5_ADDRESS_IPPORT     ) & 0xFF;
1519ebfedea0SLionel Sambuc     *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF;
1520ebfedea0SLionel Sambuc 
1521ebfedea0SLionel Sambuc     *p++ = (2      ) & 0xFF;
1522ebfedea0SLionel Sambuc     *p++ = (2 >>  8) & 0xFF;
1523ebfedea0SLionel Sambuc     *p++ = (2 >> 16) & 0xFF;
1524ebfedea0SLionel Sambuc     *p++ = (2 >> 24) & 0xFF;
1525ebfedea0SLionel Sambuc 
1526ebfedea0SLionel Sambuc     memcpy (p, &port, 2);
1527ebfedea0SLionel Sambuc 
1528ebfedea0SLionel Sambuc     return 0;
1529ebfedea0SLionel Sambuc }
1530ebfedea0SLionel Sambuc 
1531ebfedea0SLionel Sambuc /**
1532ebfedea0SLionel Sambuc  * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
1533ebfedea0SLionel Sambuc  * them in `low' and `high'.
1534ebfedea0SLionel Sambuc  *
1535ebfedea0SLionel Sambuc  * @param context a Keberos context
1536ebfedea0SLionel Sambuc  * @param inaddr address in prefixlen that the bondery searched
1537ebfedea0SLionel Sambuc  * @param prefixlen width of boundery
1538ebfedea0SLionel Sambuc  * @param low lowest address
1539ebfedea0SLionel Sambuc  * @param high highest address
1540ebfedea0SLionel Sambuc  *
1541ebfedea0SLionel Sambuc  * @return Return an error code or 0.
1542ebfedea0SLionel Sambuc  *
1543ebfedea0SLionel Sambuc  * @ingroup krb5_address
1544ebfedea0SLionel Sambuc  */
1545ebfedea0SLionel Sambuc 
1546ebfedea0SLionel Sambuc KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_address_prefixlen_boundary(krb5_context context,const krb5_address * inaddr,unsigned long prefixlen,krb5_address * low,krb5_address * high)1547ebfedea0SLionel Sambuc krb5_address_prefixlen_boundary(krb5_context context,
1548ebfedea0SLionel Sambuc 				const krb5_address *inaddr,
1549ebfedea0SLionel Sambuc 				unsigned long prefixlen,
1550ebfedea0SLionel Sambuc 				krb5_address *low,
1551ebfedea0SLionel Sambuc 				krb5_address *high)
1552ebfedea0SLionel Sambuc {
1553ebfedea0SLionel Sambuc     struct addr_operations *a = find_atype (inaddr->addr_type);
1554ebfedea0SLionel Sambuc     if(a != NULL && a->mask_boundary != NULL)
1555ebfedea0SLionel Sambuc 	return (*a->mask_boundary)(context, inaddr, prefixlen, low, high);
1556ebfedea0SLionel Sambuc     krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
1557ebfedea0SLionel Sambuc 			   N_("Address family %d doesn't support "
1558ebfedea0SLionel Sambuc 			      "address mask operation", ""),
1559ebfedea0SLionel Sambuc 			   inaddr->addr_type);
1560ebfedea0SLionel Sambuc     return KRB5_PROG_ATYPE_NOSUPP;
1561ebfedea0SLionel Sambuc }
1562