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