~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/addr_families.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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,
 
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,
 
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,
 
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)
 
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)
 
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)
 
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)
 
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,
 
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)
 
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)
 
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,
 
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,
 
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,
 
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)
 
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)
 
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)
 
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)
 
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,
 
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,
 
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)
 
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,
 
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)
 
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,
 
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)
 
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)
 
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)
 
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,
 
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,
 
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,
 
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)
 
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)
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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,
 
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
}