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