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