155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3555682Smarkm
3655682Smarkmstruct addr_operations {
3755682Smarkm    int af;
3855682Smarkm    krb5_address_type atype;
3955682Smarkm    size_t max_sockaddr_size;
4055682Smarkm    krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *);
4155682Smarkm    krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *);
4255682Smarkm    void (*addr2sockaddr)(const krb5_address *, struct sockaddr *,
43102644Snectar			  krb5_socklen_t *sa_size, int port);
44102644Snectar    void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int);
4555682Smarkm    krb5_error_code (*h_addr2addr)(const char *, krb5_address *);
4655682Smarkm    krb5_boolean (*uninteresting)(const struct sockaddr *);
47233294Sstas    krb5_boolean (*is_loopback)(const struct sockaddr *);
48102644Snectar    void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, int);
4955682Smarkm    int (*print_addr)(const krb5_address *, char *, size_t);
5090926Snectar    int (*parse_addr)(krb5_context, const char*, krb5_address *);
5190926Snectar    int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*);
5290926Snectar    int (*free_addr)(krb5_context, krb5_address*);
5390926Snectar    int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*);
54233294Sstas    int (*mask_boundary)(krb5_context, const krb5_address*, unsigned long,
55233294Sstas			 krb5_address*, krb5_address*);
5655682Smarkm};
5755682Smarkm
5855682Smarkm/*
5955682Smarkm * AF_INET - aka IPv4 implementation
6055682Smarkm */
6155682Smarkm
6255682Smarkmstatic krb5_error_code
6355682Smarkmipv4_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
6455682Smarkm{
65178825Sdfr    const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
6655682Smarkm    unsigned char buf[4];
6755682Smarkm
6855682Smarkm    a->addr_type = KRB5_ADDRESS_INET;
69178825Sdfr    memcpy (buf, &sin4->sin_addr, 4);
7055682Smarkm    return krb5_data_copy(&a->address, buf, 4);
7155682Smarkm}
7255682Smarkm
7355682Smarkmstatic krb5_error_code
7455682Smarkmipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port)
7555682Smarkm{
76178825Sdfr    const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
7755682Smarkm
78178825Sdfr    *port = sin4->sin_port;
7955682Smarkm    return 0;
8055682Smarkm}
8155682Smarkm
8255682Smarkmstatic void
8355682Smarkmipv4_addr2sockaddr (const krb5_address *a,
8455682Smarkm		    struct sockaddr *sa,
85102644Snectar		    krb5_socklen_t *sa_size,
8655682Smarkm		    int port)
8755682Smarkm{
88102644Snectar    struct sockaddr_in tmp;
8955682Smarkm
90102644Snectar    memset (&tmp, 0, sizeof(tmp));
91102644Snectar    tmp.sin_family = AF_INET;
92102644Snectar    memcpy (&tmp.sin_addr, a->address.data, 4);
93102644Snectar    tmp.sin_port = port;
94102644Snectar    memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
95102644Snectar    *sa_size = sizeof(tmp);
9655682Smarkm}
9755682Smarkm
9855682Smarkmstatic void
9955682Smarkmipv4_h_addr2sockaddr(const char *addr,
100102644Snectar		     struct sockaddr *sa,
101102644Snectar		     krb5_socklen_t *sa_size,
102102644Snectar		     int port)
10355682Smarkm{
104102644Snectar    struct sockaddr_in tmp;
10555682Smarkm
106102644Snectar    memset (&tmp, 0, sizeof(tmp));
107102644Snectar    tmp.sin_family = AF_INET;
108102644Snectar    tmp.sin_port   = port;
109102644Snectar    tmp.sin_addr   = *((const struct in_addr *)addr);
110102644Snectar    memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
111102644Snectar    *sa_size = sizeof(tmp);
11255682Smarkm}
11355682Smarkm
11455682Smarkmstatic krb5_error_code
11555682Smarkmipv4_h_addr2addr (const char *addr,
11655682Smarkm		  krb5_address *a)
11755682Smarkm{
11855682Smarkm    unsigned char buf[4];
11955682Smarkm
12055682Smarkm    a->addr_type = KRB5_ADDRESS_INET;
12155682Smarkm    memcpy(buf, addr, 4);
12255682Smarkm    return krb5_data_copy(&a->address, buf, 4);
12355682Smarkm}
12455682Smarkm
12555682Smarkm/*
12655682Smarkm * Are there any addresses that should be considered `uninteresting'?
12755682Smarkm */
12855682Smarkm
12955682Smarkmstatic krb5_boolean
13055682Smarkmipv4_uninteresting (const struct sockaddr *sa)
13155682Smarkm{
132178825Sdfr    const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
13355682Smarkm
134178825Sdfr    if (sin4->sin_addr.s_addr == INADDR_ANY)
13555682Smarkm	return TRUE;
13655682Smarkm
13755682Smarkm    return FALSE;
13855682Smarkm}
13955682Smarkm
140233294Sstasstatic krb5_boolean
141233294Sstasipv4_is_loopback (const struct sockaddr *sa)
142233294Sstas{
143233294Sstas    const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
144233294Sstas
145233294Sstas    if ((ntohl(sin4->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET)
146233294Sstas	return TRUE;
147233294Sstas
148233294Sstas    return FALSE;
149233294Sstas}
150233294Sstas
15155682Smarkmstatic void
152102644Snectaripv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
15355682Smarkm{
154102644Snectar    struct sockaddr_in tmp;
15555682Smarkm
156102644Snectar    memset (&tmp, 0, sizeof(tmp));
157102644Snectar    tmp.sin_family = AF_INET;
158102644Snectar    tmp.sin_port   = port;
159102644Snectar    tmp.sin_addr.s_addr = INADDR_ANY;
160102644Snectar    memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
161102644Snectar    *sa_size = sizeof(tmp);
16255682Smarkm}
16355682Smarkm
16455682Smarkmstatic int
16555682Smarkmipv4_print_addr (const krb5_address *addr, char *str, size_t len)
16655682Smarkm{
16755682Smarkm    struct in_addr ia;
16855682Smarkm
16955682Smarkm    memcpy (&ia, addr->address.data, 4);
17055682Smarkm
17155682Smarkm    return snprintf (str, len, "IPv4:%s", inet_ntoa(ia));
17255682Smarkm}
17355682Smarkm
17455682Smarkmstatic int
17590926Snectaripv4_parse_addr (krb5_context context, const char *address, krb5_address *addr)
17655682Smarkm{
17755682Smarkm    const char *p;
17855682Smarkm    struct in_addr a;
17955682Smarkm
18055682Smarkm    p = strchr(address, ':');
18155682Smarkm    if(p) {
18255682Smarkm	p++;
18355682Smarkm	if(strncasecmp(address, "ip:", p - address) != 0 &&
18455682Smarkm	   strncasecmp(address, "ip4:", p - address) != 0 &&
18555682Smarkm	   strncasecmp(address, "ipv4:", p - address) != 0 &&
18655682Smarkm	   strncasecmp(address, "inet:", p - address) != 0)
18755682Smarkm	    return -1;
18855682Smarkm    } else
18955682Smarkm	p = address;
19055682Smarkm    if(inet_aton(p, &a) == 0)
19155682Smarkm	return -1;
19255682Smarkm    addr->addr_type = KRB5_ADDRESS_INET;
19355682Smarkm    if(krb5_data_alloc(&addr->address, 4) != 0)
19455682Smarkm	return -1;
19555682Smarkm    _krb5_put_int(addr->address.data, ntohl(a.s_addr), addr->address.length);
19655682Smarkm    return 0;
19755682Smarkm}
19855682Smarkm
199178825Sdfrstatic int
200178825Sdfripv4_mask_boundary(krb5_context context, const krb5_address *inaddr,
201178825Sdfr		   unsigned long len, krb5_address *low, krb5_address *high)
202178825Sdfr{
203178825Sdfr    unsigned long ia;
204178825Sdfr    uint32_t l, h, m = 0xffffffff;
205178825Sdfr
206178825Sdfr    if (len > 32) {
207233294Sstas	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
208233294Sstas			       N_("IPv4 prefix too large (%ld)", "len"), len);
209178825Sdfr	return KRB5_PROG_ATYPE_NOSUPP;
210178825Sdfr    }
211178825Sdfr    m = m << (32 - len);
212178825Sdfr
213178825Sdfr    _krb5_get_int(inaddr->address.data, &ia, inaddr->address.length);
214178825Sdfr
215178825Sdfr    l = ia & m;
216178825Sdfr    h = l | ~m;
217178825Sdfr
218178825Sdfr    low->addr_type = KRB5_ADDRESS_INET;
219178825Sdfr    if(krb5_data_alloc(&low->address, 4) != 0)
220178825Sdfr	return -1;
221178825Sdfr    _krb5_put_int(low->address.data, l, low->address.length);
222178825Sdfr
223178825Sdfr    high->addr_type = KRB5_ADDRESS_INET;
224178825Sdfr    if(krb5_data_alloc(&high->address, 4) != 0) {
225178825Sdfr	krb5_free_address(context, low);
226178825Sdfr	return -1;
227178825Sdfr    }
228178825Sdfr    _krb5_put_int(high->address.data, h, high->address.length);
229178825Sdfr
230178825Sdfr    return 0;
231178825Sdfr}
232178825Sdfr
233178825Sdfr
23455682Smarkm/*
23555682Smarkm * AF_INET6 - aka IPv6 implementation
23655682Smarkm */
23755682Smarkm
23855682Smarkm#ifdef HAVE_IPV6
23955682Smarkm
24055682Smarkmstatic krb5_error_code
24155682Smarkmipv6_sockaddr2addr (const struct sockaddr *sa, krb5_address *a)
24255682Smarkm{
24355682Smarkm    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
24455682Smarkm
24555682Smarkm    if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
24655682Smarkm	unsigned char buf[4];
24755682Smarkm
24855682Smarkm	a->addr_type      = KRB5_ADDRESS_INET;
24955682Smarkm#ifndef IN6_ADDR_V6_TO_V4
25055682Smarkm#ifdef IN6_EXTRACT_V4ADDR
25155682Smarkm#define IN6_ADDR_V6_TO_V4(x) (&IN6_EXTRACT_V4ADDR(x))
25255682Smarkm#else
25355682Smarkm#define IN6_ADDR_V6_TO_V4(x) ((const struct in_addr *)&(x)->s6_addr[12])
25455682Smarkm#endif
25555682Smarkm#endif
25655682Smarkm	memcpy (buf, IN6_ADDR_V6_TO_V4(&sin6->sin6_addr), 4);
25755682Smarkm	return krb5_data_copy(&a->address, buf, 4);
25855682Smarkm    } else {
25955682Smarkm	a->addr_type = KRB5_ADDRESS_INET6;
26055682Smarkm	return krb5_data_copy(&a->address,
26155682Smarkm			      &sin6->sin6_addr,
26255682Smarkm			      sizeof(sin6->sin6_addr));
26355682Smarkm    }
26455682Smarkm}
26555682Smarkm
26655682Smarkmstatic krb5_error_code
26755682Smarkmipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port)
26855682Smarkm{
26955682Smarkm    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
27055682Smarkm
27155682Smarkm    *port = sin6->sin6_port;
27255682Smarkm    return 0;
27355682Smarkm}
27455682Smarkm
27555682Smarkmstatic void
27655682Smarkmipv6_addr2sockaddr (const krb5_address *a,
27755682Smarkm		    struct sockaddr *sa,
278102644Snectar		    krb5_socklen_t *sa_size,
27955682Smarkm		    int port)
28055682Smarkm{
281102644Snectar    struct sockaddr_in6 tmp;
28255682Smarkm
283102644Snectar    memset (&tmp, 0, sizeof(tmp));
284102644Snectar    tmp.sin6_family = AF_INET6;
285102644Snectar    memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr));
286102644Snectar    tmp.sin6_port = port;
287102644Snectar    memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
288102644Snectar    *sa_size = sizeof(tmp);
28955682Smarkm}
29055682Smarkm
29155682Smarkmstatic void
29255682Smarkmipv6_h_addr2sockaddr(const char *addr,
29355682Smarkm		     struct sockaddr *sa,
294102644Snectar		     krb5_socklen_t *sa_size,
29555682Smarkm		     int port)
29655682Smarkm{
297102644Snectar    struct sockaddr_in6 tmp;
29855682Smarkm
299102644Snectar    memset (&tmp, 0, sizeof(tmp));
300102644Snectar    tmp.sin6_family = AF_INET6;
301102644Snectar    tmp.sin6_port   = port;
302102644Snectar    tmp.sin6_addr   = *((const struct in6_addr *)addr);
303102644Snectar    memcpy(sa, &tmp, min(sizeof(tmp), *sa_size));
304102644Snectar    *sa_size = sizeof(tmp);
30555682Smarkm}
30655682Smarkm
30755682Smarkmstatic krb5_error_code
30855682Smarkmipv6_h_addr2addr (const char *addr,
30955682Smarkm		  krb5_address *a)
31055682Smarkm{
31155682Smarkm    a->addr_type = KRB5_ADDRESS_INET6;
31255682Smarkm    return krb5_data_copy(&a->address, addr, sizeof(struct in6_addr));
31355682Smarkm}
31455682Smarkm
31555682Smarkm/*
316233294Sstas *
31755682Smarkm */
31855682Smarkm
31955682Smarkmstatic krb5_boolean
32055682Smarkmipv6_uninteresting (const struct sockaddr *sa)
32155682Smarkm{
32255682Smarkm    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
32355682Smarkm    const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
324233294Sstas
325233294Sstas    return IN6_IS_ADDR_LINKLOCAL(in6)
32655682Smarkm	|| IN6_IS_ADDR_V4COMPAT(in6);
32755682Smarkm}
32855682Smarkm
329233294Sstasstatic krb5_boolean
330233294Sstasipv6_is_loopback (const struct sockaddr *sa)
331233294Sstas{
332233294Sstas    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
333233294Sstas    const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;
334233294Sstas
335233294Sstas    return (IN6_IS_ADDR_LOOPBACK(in6));
336233294Sstas}
337233294Sstas
33855682Smarkmstatic void
339102644Snectaripv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port)
34055682Smarkm{
341102644Snectar    struct sockaddr_in6 tmp;
34255682Smarkm
343102644Snectar    memset (&tmp, 0, sizeof(tmp));
344102644Snectar    tmp.sin6_family = AF_INET6;
345102644Snectar    tmp.sin6_port   = port;
346102644Snectar    tmp.sin6_addr   = in6addr_any;
347102644Snectar    *sa_size = sizeof(tmp);
34855682Smarkm}
34955682Smarkm
35055682Smarkmstatic int
35155682Smarkmipv6_print_addr (const krb5_address *addr, char *str, size_t len)
35255682Smarkm{
35355682Smarkm    char buf[128], buf2[3];
35455682Smarkm    if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL)
35555682Smarkm	{
35655682Smarkm	    /* XXX this is pretty ugly, but better than abort() */
357233294Sstas	    size_t i;
35855682Smarkm	    unsigned char *p = addr->address.data;
35955682Smarkm	    buf[0] = '\0';
36055682Smarkm	    for(i = 0; i < addr->address.length; i++) {
36155682Smarkm		snprintf(buf2, sizeof(buf2), "%02x", p[i]);
36255682Smarkm		if(i > 0 && (i & 1) == 0)
36355682Smarkm		    strlcat(buf, ":", sizeof(buf));
36455682Smarkm		strlcat(buf, buf2, sizeof(buf));
36555682Smarkm	    }
36655682Smarkm	}
36755682Smarkm    return snprintf(str, len, "IPv6:%s", buf);
36855682Smarkm}
36955682Smarkm
37055682Smarkmstatic int
37190926Snectaripv6_parse_addr (krb5_context context, const char *address, krb5_address *addr)
37255682Smarkm{
37355682Smarkm    int ret;
37455682Smarkm    struct in6_addr in6;
37590926Snectar    const char *p;
37655682Smarkm
37790926Snectar    p = strchr(address, ':');
37890926Snectar    if(p) {
37990926Snectar	p++;
38090926Snectar	if(strncasecmp(address, "ip6:", p - address) == 0 ||
38190926Snectar	   strncasecmp(address, "ipv6:", p - address) == 0 ||
38290926Snectar	   strncasecmp(address, "inet6:", p - address) == 0)
38390926Snectar	    address = p;
38490926Snectar    }
38590926Snectar
38655682Smarkm    ret = inet_pton(AF_INET6, address, &in6.s6_addr);
38755682Smarkm    if(ret == 1) {
38855682Smarkm	addr->addr_type = KRB5_ADDRESS_INET6;
38955682Smarkm	ret = krb5_data_alloc(&addr->address, sizeof(in6.s6_addr));
39055682Smarkm	if (ret)
39155682Smarkm	    return -1;
39255682Smarkm	memcpy(addr->address.data, in6.s6_addr, sizeof(in6.s6_addr));
39355682Smarkm	return 0;
39455682Smarkm    }
39555682Smarkm    return -1;
39655682Smarkm}
39755682Smarkm
398178825Sdfrstatic int
399178825Sdfripv6_mask_boundary(krb5_context context, const krb5_address *inaddr,
400178825Sdfr		   unsigned long len, krb5_address *low, krb5_address *high)
401178825Sdfr{
402178825Sdfr    struct in6_addr addr, laddr, haddr;
403178825Sdfr    uint32_t m;
404178825Sdfr    int i, sub_len;
405178825Sdfr
406178825Sdfr    if (len > 128) {
407233294Sstas	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
408233294Sstas			       N_("IPv6 prefix too large (%ld)", "length"), len);
409178825Sdfr	return KRB5_PROG_ATYPE_NOSUPP;
410178825Sdfr    }
411178825Sdfr
412178825Sdfr    if (inaddr->address.length != sizeof(addr)) {
413233294Sstas	krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
414233294Sstas			       N_("IPv6 addr bad length", ""));
415178825Sdfr	return KRB5_PROG_ATYPE_NOSUPP;
416178825Sdfr    }
417178825Sdfr
418178825Sdfr    memcpy(&addr, inaddr->address.data, inaddr->address.length);
419178825Sdfr
420178825Sdfr    for (i = 0; i < 16; i++) {
421178825Sdfr	sub_len = min(8, len);
422178825Sdfr
423178825Sdfr	m = 0xff << (8 - sub_len);
424233294Sstas
425178825Sdfr	laddr.s6_addr[i] = addr.s6_addr[i] & m;
426178825Sdfr	haddr.s6_addr[i] = (addr.s6_addr[i] & m) | ~m;
427178825Sdfr
428178825Sdfr	if (len > 8)
429178825Sdfr	    len -= 8;
430178825Sdfr	else
431178825Sdfr	    len = 0;
432178825Sdfr    }
433178825Sdfr
434178825Sdfr    low->addr_type = KRB5_ADDRESS_INET6;
435178825Sdfr    if (krb5_data_alloc(&low->address, sizeof(laddr.s6_addr)) != 0)
436178825Sdfr	return -1;
437178825Sdfr    memcpy(low->address.data, laddr.s6_addr, sizeof(laddr.s6_addr));
438178825Sdfr
439178825Sdfr    high->addr_type = KRB5_ADDRESS_INET6;
440178825Sdfr    if (krb5_data_alloc(&high->address, sizeof(haddr.s6_addr)) != 0) {
441178825Sdfr	krb5_free_address(context, low);
442178825Sdfr	return -1;
443178825Sdfr    }
444178825Sdfr    memcpy(high->address.data, haddr.s6_addr, sizeof(haddr.s6_addr));
445178825Sdfr
446178825Sdfr    return 0;
447178825Sdfr}
448178825Sdfr
44955682Smarkm#endif /* IPv6 */
45055682Smarkm
451233294Sstas#ifndef HEIMDAL_SMALLER
452233294Sstas
45355682Smarkm/*
45455682Smarkm * table
45555682Smarkm */
45655682Smarkm
45790926Snectar#define KRB5_ADDRESS_ARANGE	(-100)
45890926Snectar
45990926Snectarstruct arange {
46090926Snectar    krb5_address low;
46190926Snectar    krb5_address high;
46290926Snectar};
46390926Snectar
46490926Snectarstatic int
465233294Sstasarange_parse_addr (krb5_context context,
466102644Snectar		   const char *address, krb5_address *addr)
46790926Snectar{
468178825Sdfr    char buf[1024], *p;
469178825Sdfr    krb5_address low0, high0;
47090926Snectar    struct arange *a;
47190926Snectar    krb5_error_code ret;
472233294Sstas
47390926Snectar    if(strncasecmp(address, "RANGE:", 6) != 0)
47490926Snectar	return -1;
475233294Sstas
47690926Snectar    address += 6;
47790926Snectar
478178825Sdfr    p = strrchr(address, '/');
479178825Sdfr    if (p) {
480178825Sdfr	krb5_addresses addrmask;
481178825Sdfr	char *q;
482178825Sdfr	long num;
48390926Snectar
484178825Sdfr	if (strlcpy(buf, address, sizeof(buf)) > sizeof(buf))
485178825Sdfr	    return -1;
486178825Sdfr	buf[p - address] = '\0';
487178825Sdfr	ret = krb5_parse_address(context, buf, &addrmask);
488178825Sdfr	if (ret)
489178825Sdfr	    return ret;
490178825Sdfr	if(addrmask.len != 1) {
491178825Sdfr	    krb5_free_addresses(context, &addrmask);
492178825Sdfr	    return -1;
493178825Sdfr	}
494233294Sstas
495178825Sdfr	address += p - address + 1;
49690926Snectar
497178825Sdfr	num = strtol(address, &q, 10);
498178825Sdfr	if (q == address || *q != '\0' || num < 0) {
499178825Sdfr	    krb5_free_addresses(context, &addrmask);
500178825Sdfr	    return -1;
501178825Sdfr	}
502178825Sdfr
503178825Sdfr	ret = krb5_address_prefixlen_boundary(context, &addrmask.val[0], num,
504178825Sdfr					      &low0, &high0);
505178825Sdfr	krb5_free_addresses(context, &addrmask);
506178825Sdfr	if (ret)
507178825Sdfr	    return ret;
508178825Sdfr
509178825Sdfr    } else {
510178825Sdfr	krb5_addresses low, high;
511233294Sstas
512178825Sdfr	strsep_copy(&address, "-", buf, sizeof(buf));
513178825Sdfr	ret = krb5_parse_address(context, buf, &low);
514178825Sdfr	if(ret)
515178825Sdfr	    return ret;
516178825Sdfr	if(low.len != 1) {
517178825Sdfr	    krb5_free_addresses(context, &low);
518178825Sdfr	    return -1;
519178825Sdfr	}
520233294Sstas
521178825Sdfr	strsep_copy(&address, "-", buf, sizeof(buf));
522178825Sdfr	ret = krb5_parse_address(context, buf, &high);
523178825Sdfr	if(ret) {
524178825Sdfr	    krb5_free_addresses(context, &low);
525178825Sdfr	    return ret;
526178825Sdfr	}
527233294Sstas
528178825Sdfr	if(high.len != 1 && high.val[0].addr_type != low.val[0].addr_type) {
529178825Sdfr	    krb5_free_addresses(context, &low);
530178825Sdfr	    krb5_free_addresses(context, &high);
531178825Sdfr	    return -1;
532178825Sdfr	}
533178825Sdfr
534178825Sdfr	ret = krb5_copy_address(context, &high.val[0], &high0);
535178825Sdfr	if (ret == 0) {
536178825Sdfr	    ret = krb5_copy_address(context, &low.val[0], &low0);
537178825Sdfr	    if (ret)
538178825Sdfr		krb5_free_address(context, &high0);
539178825Sdfr	}
54090926Snectar	krb5_free_addresses(context, &low);
54190926Snectar	krb5_free_addresses(context, &high);
542178825Sdfr	if (ret)
543178825Sdfr	    return ret;
54490926Snectar    }
54590926Snectar
54690926Snectar    krb5_data_alloc(&addr->address, sizeof(*a));
54790926Snectar    addr->addr_type = KRB5_ADDRESS_ARANGE;
54890926Snectar    a = addr->address.data;
54990926Snectar
550178825Sdfr    if(krb5_address_order(context, &low0, &high0) < 0) {
551178825Sdfr	a->low = low0;
552178825Sdfr	a->high = high0;
55390926Snectar    } else {
554178825Sdfr	a->low = high0;
555178825Sdfr	a->high = low0;
55690926Snectar    }
55790926Snectar    return 0;
55890926Snectar}
55990926Snectar
56090926Snectarstatic int
56190926Snectararange_free (krb5_context context, krb5_address *addr)
56290926Snectar{
56390926Snectar    struct arange *a;
56490926Snectar    a = addr->address.data;
56590926Snectar    krb5_free_address(context, &a->low);
56690926Snectar    krb5_free_address(context, &a->high);
567178825Sdfr    krb5_data_free(&addr->address);
56890926Snectar    return 0;
56990926Snectar}
57090926Snectar
57190926Snectar
57290926Snectarstatic int
573233294Sstasarange_copy (krb5_context context, const krb5_address *inaddr,
57490926Snectar	     krb5_address *outaddr)
57590926Snectar{
57690926Snectar    krb5_error_code ret;
57790926Snectar    struct arange *i, *o;
57890926Snectar
57990926Snectar    outaddr->addr_type = KRB5_ADDRESS_ARANGE;
58090926Snectar    ret = krb5_data_alloc(&outaddr->address, sizeof(*o));
58190926Snectar    if(ret)
58290926Snectar	return ret;
58390926Snectar    i = inaddr->address.data;
58490926Snectar    o = outaddr->address.data;
58590926Snectar    ret = krb5_copy_address(context, &i->low, &o->low);
58690926Snectar    if(ret) {
58790926Snectar	krb5_data_free(&outaddr->address);
58890926Snectar	return ret;
58990926Snectar    }
59090926Snectar    ret = krb5_copy_address(context, &i->high, &o->high);
59190926Snectar    if(ret) {
59290926Snectar	krb5_free_address(context, &o->low);
59390926Snectar	krb5_data_free(&outaddr->address);
59490926Snectar	return ret;
59590926Snectar    }
59690926Snectar    return 0;
59790926Snectar}
59890926Snectar
59990926Snectarstatic int
60090926Snectararange_print_addr (const krb5_address *addr, char *str, size_t len)
60190926Snectar{
60290926Snectar    struct arange *a;
60390926Snectar    krb5_error_code ret;
604178825Sdfr    size_t l, size, ret_len;
60590926Snectar
60690926Snectar    a = addr->address.data;
60790926Snectar
60890926Snectar    l = strlcpy(str, "RANGE:", len);
609178825Sdfr    ret_len = l;
610178825Sdfr    if (l > len)
611178825Sdfr	l = len;
612178825Sdfr    size = l;
613233294Sstas
614178825Sdfr    ret = krb5_print_address (&a->low, str + size, len - size, &l);
615178825Sdfr    if (ret)
616178825Sdfr	return ret;
61790926Snectar    ret_len += l;
618178825Sdfr    if (len - size > l)
619178825Sdfr	size += l;
620178825Sdfr    else
621178825Sdfr	size = len;
62290926Snectar
623178825Sdfr    l = strlcat(str + size, "-", len - size);
62490926Snectar    ret_len += l;
625178825Sdfr    if (len - size > l)
626178825Sdfr	size += l;
627178825Sdfr    else
628178825Sdfr	size = len;
62990926Snectar
630178825Sdfr    ret = krb5_print_address (&a->high, str + size, len - size, &l);
631178825Sdfr    if (ret)
632178825Sdfr	return ret;
63390926Snectar    ret_len += l;
63490926Snectar
63590926Snectar    return ret_len;
63690926Snectar}
63790926Snectar
63890926Snectarstatic int
639233294Sstasarange_order_addr(krb5_context context,
640233294Sstas		  const krb5_address *addr1,
641102644Snectar		  const krb5_address *addr2)
64290926Snectar{
64390926Snectar    int tmp1, tmp2, sign;
64490926Snectar    struct arange *a;
64590926Snectar    const krb5_address *a2;
64690926Snectar
64790926Snectar    if(addr1->addr_type == KRB5_ADDRESS_ARANGE) {
64890926Snectar	a = addr1->address.data;
64990926Snectar	a2 = addr2;
65090926Snectar	sign = 1;
65190926Snectar    } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) {
65290926Snectar	a = addr2->address.data;
65390926Snectar	a2 = addr1;
65490926Snectar	sign = -1;
655233294Sstas    } else {
65690926Snectar	abort();
657233294Sstas        UNREACHABLE(return 0);
658233294Sstas    }
659233294Sstas
66090926Snectar    if(a2->addr_type == KRB5_ADDRESS_ARANGE) {
66190926Snectar	struct arange *b = a2->address.data;
66290926Snectar	tmp1 = krb5_address_order(context, &a->low, &b->low);
66390926Snectar	if(tmp1 != 0)
66490926Snectar	    return sign * tmp1;
66590926Snectar	return sign * krb5_address_order(context, &a->high, &b->high);
66690926Snectar    } else if(a2->addr_type == a->low.addr_type) {
66790926Snectar	tmp1 = krb5_address_order(context, &a->low, a2);
66890926Snectar	if(tmp1 > 0)
66990926Snectar	    return sign;
67090926Snectar	tmp2 = krb5_address_order(context, &a->high, a2);
67190926Snectar	if(tmp2 < 0)
67290926Snectar	    return -sign;
67390926Snectar	return 0;
67490926Snectar    } else {
67590926Snectar	return sign * (addr1->addr_type - addr2->addr_type);
67690926Snectar    }
67790926Snectar}
67890926Snectar
679233294Sstas#endif /* HEIMDAL_SMALLER */
680233294Sstas
681120945Snectarstatic int
682120945Snectaraddrport_print_addr (const krb5_address *addr, char *str, size_t len)
683120945Snectar{
684178825Sdfr    krb5_error_code ret;
685120945Snectar    krb5_address addr1, addr2;
686120945Snectar    uint16_t port = 0;
687178825Sdfr    size_t ret_len = 0, l, size = 0;
688178825Sdfr    krb5_storage *sp;
689178825Sdfr
690178825Sdfr    sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address));
691233294Sstas    if (sp == NULL)
692233294Sstas        return ENOMEM;
693233294Sstas
694120945Snectar    /* for totally obscure reasons, these are not in network byteorder */
695120945Snectar    krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE);
696120945Snectar
697120945Snectar    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */
698120945Snectar    krb5_ret_address(sp, &addr1);
699120945Snectar
700120945Snectar    krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */
701120945Snectar    krb5_ret_address(sp, &addr2);
702120945Snectar    krb5_storage_free(sp);
703120945Snectar    if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) {
704120945Snectar	unsigned long value;
705120945Snectar	_krb5_get_int(addr2.address.data, &value, 2);
706120945Snectar	port = value;
707120945Snectar    }
708120945Snectar    l = strlcpy(str, "ADDRPORT:", len);
709120945Snectar    ret_len += l;
710178825Sdfr    if (len > l)
711178825Sdfr	size += l;
712178825Sdfr    else
713178825Sdfr	size = len;
714178825Sdfr
715178825Sdfr    ret = krb5_print_address(&addr1, str + size, len - size, &l);
716178825Sdfr    if (ret)
717178825Sdfr	return ret;
718120945Snectar    ret_len += l;
719178825Sdfr    if (len - size > l)
720178825Sdfr	size += l;
721178825Sdfr    else
722178825Sdfr	size = len;
723178825Sdfr
724178825Sdfr    ret = snprintf(str + size, len - size, ",PORT=%u", port);
725178825Sdfr    if (ret < 0)
726178825Sdfr	return EINVAL;
727178825Sdfr    ret_len += ret;
728120945Snectar    return ret_len;
729120945Snectar}
730120945Snectar
73155682Smarkmstatic struct addr_operations at[] = {
732233294Sstas    {
733233294Sstas	AF_INET,	KRB5_ADDRESS_INET, sizeof(struct sockaddr_in),
734233294Sstas	ipv4_sockaddr2addr,
735233294Sstas	ipv4_sockaddr2port,
736233294Sstas	ipv4_addr2sockaddr,
737233294Sstas	ipv4_h_addr2sockaddr,
738233294Sstas	ipv4_h_addr2addr,
739233294Sstas	ipv4_uninteresting,
740233294Sstas	ipv4_is_loopback,
741233294Sstas	ipv4_anyaddr,
742233294Sstas	ipv4_print_addr,
743233294Sstas	ipv4_parse_addr,
744233294Sstas	NULL,
745233294Sstas	NULL,
746233294Sstas	NULL,
747233294Sstas     ipv4_mask_boundary
748233294Sstas    },
74955682Smarkm#ifdef HAVE_IPV6
750233294Sstas    {
751233294Sstas	AF_INET6,	KRB5_ADDRESS_INET6, sizeof(struct sockaddr_in6),
752233294Sstas	ipv6_sockaddr2addr,
753233294Sstas	ipv6_sockaddr2port,
754233294Sstas	ipv6_addr2sockaddr,
755233294Sstas	ipv6_h_addr2sockaddr,
756233294Sstas	ipv6_h_addr2addr,
757233294Sstas	ipv6_uninteresting,
758233294Sstas	ipv6_is_loopback,
759233294Sstas	ipv6_anyaddr,
760233294Sstas	ipv6_print_addr,
761233294Sstas	ipv6_parse_addr,
762233294Sstas	NULL,
763233294Sstas	NULL,
764233294Sstas	NULL,
765233294Sstas	ipv6_mask_boundary
766233294Sstas    } ,
76755682Smarkm#endif
768233294Sstas#ifndef HEIMDAL_SMALLER
76990926Snectar    /* fake address type */
770233294Sstas    {
771233294Sstas	KRB5_ADDRESS_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange),
772233294Sstas	NULL,
773233294Sstas	NULL,
774233294Sstas	NULL,
775233294Sstas	NULL,
776233294Sstas	NULL,
777233294Sstas	NULL,
778233294Sstas	NULL,
779233294Sstas	NULL,
780233294Sstas	arange_print_addr,
781233294Sstas	arange_parse_addr,
782233294Sstas	arange_order_addr,
783233294Sstas	arange_free,
784233294Sstas	arange_copy,
785233294Sstas	NULL
786233294Sstas    },
787233294Sstas#endif
788233294Sstas    {
789233294Sstas	KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0,
790233294Sstas	NULL,
791233294Sstas	NULL,
792233294Sstas	NULL,
793233294Sstas	NULL,
794233294Sstas	NULL,
795233294Sstas	NULL,
796233294Sstas	NULL,
797233294Sstas	NULL,
798233294Sstas	addrport_print_addr,
799233294Sstas	NULL,
800233294Sstas	NULL,
801233294Sstas	NULL,
802233294Sstas	NULL
803233294Sstas    }
80455682Smarkm};
80555682Smarkm
80655682Smarkmstatic int num_addrs = sizeof(at) / sizeof(at[0]);
80755682Smarkm
80855682Smarkmstatic size_t max_sockaddr_size = 0;
80955682Smarkm
81055682Smarkm/*
81155682Smarkm * generic functions
81255682Smarkm */
81355682Smarkm
81455682Smarkmstatic struct addr_operations *
81555682Smarkmfind_af(int af)
81655682Smarkm{
81755682Smarkm    struct addr_operations *a;
81855682Smarkm
81955682Smarkm    for (a = at; a < at + num_addrs; ++a)
82055682Smarkm	if (af == a->af)
82155682Smarkm	    return a;
82255682Smarkm    return NULL;
82355682Smarkm}
82455682Smarkm
82555682Smarkmstatic struct addr_operations *
826233294Sstasfind_atype(krb5_address_type atype)
82755682Smarkm{
82855682Smarkm    struct addr_operations *a;
82955682Smarkm
83055682Smarkm    for (a = at; a < at + num_addrs; ++a)
83155682Smarkm	if (atype == a->atype)
83255682Smarkm	    return a;
83355682Smarkm    return NULL;
83455682Smarkm}
83555682Smarkm
836178825Sdfr/**
837178825Sdfr * krb5_sockaddr2address stores a address a "struct sockaddr" sa in
838233294Sstas * the krb5_address addr.
839178825Sdfr *
840178825Sdfr * @param context a Keberos context
841178825Sdfr * @param sa a struct sockaddr to extract the address from
842178825Sdfr * @param addr an Kerberos 5 address to store the address in.
843178825Sdfr *
844178825Sdfr * @return Return an error code or 0.
845178825Sdfr *
846178825Sdfr * @ingroup krb5_address
847178825Sdfr */
848178825Sdfr
849233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
85078527Sassarkrb5_sockaddr2address (krb5_context context,
85178527Sassar		       const struct sockaddr *sa, krb5_address *addr)
85255682Smarkm{
85355682Smarkm    struct addr_operations *a = find_af(sa->sa_family);
85478527Sassar    if (a == NULL) {
855233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
856233294Sstas				N_("Address family %d not supported", ""),
857233294Sstas				sa->sa_family);
85855682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
85978527Sassar    }
86055682Smarkm    return (*a->sockaddr2addr)(sa, addr);
86155682Smarkm}
86255682Smarkm
863178825Sdfr/**
864178825Sdfr * krb5_sockaddr2port extracts a port (if possible) from a "struct
865178825Sdfr * sockaddr.
866178825Sdfr *
867178825Sdfr * @param context a Keberos context
868178825Sdfr * @param sa a struct sockaddr to extract the port from
869178825Sdfr * @param port a pointer to an int16_t store the port in.
870178825Sdfr *
871178825Sdfr * @return Return an error code or 0. Will return
872178825Sdfr * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
873178825Sdfr *
874178825Sdfr * @ingroup krb5_address
875178825Sdfr */
876178825Sdfr
877233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
87878527Sassarkrb5_sockaddr2port (krb5_context context,
87978527Sassar		    const struct sockaddr *sa, int16_t *port)
88055682Smarkm{
88155682Smarkm    struct addr_operations *a = find_af(sa->sa_family);
88278527Sassar    if (a == NULL) {
883233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
884233294Sstas				N_("Address family %d not supported", ""),
885233294Sstas				sa->sa_family);
88655682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
88778527Sassar    }
88855682Smarkm    return (*a->sockaddr2port)(sa, port);
88955682Smarkm}
89055682Smarkm
891178825Sdfr/**
892178825Sdfr * krb5_addr2sockaddr sets the "struct sockaddr sockaddr" from addr
893178825Sdfr * and port. The argument sa_size should initially contain the size of
894178825Sdfr * the sa and after the call, it will contain the actual length of the
895178825Sdfr * address. In case of the sa is too small to fit the whole address,
896178825Sdfr * the up to *sa_size will be stored, and then *sa_size will be set to
897178825Sdfr * the required length.
898178825Sdfr *
899178825Sdfr * @param context a Keberos context
900178825Sdfr * @param addr the address to copy the from
901178825Sdfr * @param sa the struct sockaddr that will be filled in
902178825Sdfr * @param sa_size pointer to length of sa, and after the call, it will
903178825Sdfr * contain the actual length of the address.
904178825Sdfr * @param port set port in sa.
905178825Sdfr *
906178825Sdfr * @return Return an error code or 0. Will return
907178825Sdfr * KRB5_PROG_ATYPE_NOSUPP in case address type is not supported.
908178825Sdfr *
909178825Sdfr * @ingroup krb5_address
910178825Sdfr */
911178825Sdfr
912233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
91378527Sassarkrb5_addr2sockaddr (krb5_context context,
91478527Sassar		    const krb5_address *addr,
91555682Smarkm		    struct sockaddr *sa,
916102644Snectar		    krb5_socklen_t *sa_size,
91755682Smarkm		    int port)
91855682Smarkm{
91955682Smarkm    struct addr_operations *a = find_atype(addr->addr_type);
92055682Smarkm
92178527Sassar    if (a == NULL) {
922233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
923233294Sstas				N_("Address type %d not supported",
924233294Sstas				   "krb5_address type"),
925233294Sstas				addr->addr_type);
92655682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
92778527Sassar    }
92890926Snectar    if (a->addr2sockaddr == NULL) {
929233294Sstas	krb5_set_error_message (context,
930233294Sstas				KRB5_PROG_ATYPE_NOSUPP,
931233294Sstas				N_("Can't convert address type %d to sockaddr", ""),
932233294Sstas				addr->addr_type);
93390926Snectar	return KRB5_PROG_ATYPE_NOSUPP;
93490926Snectar    }
93555682Smarkm    (*a->addr2sockaddr)(addr, sa, sa_size, port);
93655682Smarkm    return 0;
93755682Smarkm}
93855682Smarkm
939178825Sdfr/**
940178825Sdfr * krb5_max_sockaddr_size returns the max size of the .Li struct
941178825Sdfr * sockaddr that the Kerberos library will return.
942178825Sdfr *
943178825Sdfr * @return Return an size_t of the maximum struct sockaddr.
944178825Sdfr *
945178825Sdfr * @ingroup krb5_address
946178825Sdfr */
947178825Sdfr
948233294SstasKRB5_LIB_FUNCTION size_t KRB5_LIB_CALL
94955682Smarkmkrb5_max_sockaddr_size (void)
95055682Smarkm{
95155682Smarkm    if (max_sockaddr_size == 0) {
95255682Smarkm	struct addr_operations *a;
95355682Smarkm
95455682Smarkm	for(a = at; a < at + num_addrs; ++a)
95555682Smarkm	    max_sockaddr_size = max(max_sockaddr_size, a->max_sockaddr_size);
95655682Smarkm    }
95755682Smarkm    return max_sockaddr_size;
95855682Smarkm}
95955682Smarkm
960178825Sdfr/**
961178825Sdfr * krb5_sockaddr_uninteresting returns TRUE for all .Fa sa that the
962178825Sdfr * kerberos library thinks are uninteresting.  One example are link
963178825Sdfr * local addresses.
964178825Sdfr *
965178825Sdfr * @param sa pointer to struct sockaddr that might be interesting.
966178825Sdfr *
967178825Sdfr * @return Return a non zero for uninteresting addresses.
968178825Sdfr *
969178825Sdfr * @ingroup krb5_address
970178825Sdfr */
971178825Sdfr
972233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
97355682Smarkmkrb5_sockaddr_uninteresting(const struct sockaddr *sa)
97455682Smarkm{
97555682Smarkm    struct addr_operations *a = find_af(sa->sa_family);
97690926Snectar    if (a == NULL || a->uninteresting == NULL)
97755682Smarkm	return TRUE;
97855682Smarkm    return (*a->uninteresting)(sa);
97955682Smarkm}
98055682Smarkm
981233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
982233294Sstaskrb5_sockaddr_is_loopback(const struct sockaddr *sa)
983233294Sstas{
984233294Sstas    struct addr_operations *a = find_af(sa->sa_family);
985233294Sstas    if (a == NULL || a->is_loopback == NULL)
986233294Sstas	return TRUE;
987233294Sstas    return (*a->is_loopback)(sa);
988233294Sstas}
989233294Sstas
990178825Sdfr/**
991178825Sdfr * krb5_h_addr2sockaddr initializes a "struct sockaddr sa" from af and
992178825Sdfr * the "struct hostent" (see gethostbyname(3) ) h_addr_list
993178825Sdfr * component. The argument sa_size should initially contain the size
994178825Sdfr * of the sa, and after the call, it will contain the actual length of
995178825Sdfr * the address.
996178825Sdfr *
997178825Sdfr * @param context a Keberos context
998178825Sdfr * @param af addresses
999178825Sdfr * @param addr address
1000178825Sdfr * @param sa returned struct sockaddr
1001178825Sdfr * @param sa_size size of sa
1002178825Sdfr * @param port port to set in sa.
1003178825Sdfr *
1004178825Sdfr * @return Return an error code or 0.
1005178825Sdfr *
1006178825Sdfr * @ingroup krb5_address
1007178825Sdfr */
1008178825Sdfr
1009233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
101078527Sassarkrb5_h_addr2sockaddr (krb5_context context,
101178527Sassar		      int af,
1012102644Snectar		      const char *addr, struct sockaddr *sa,
1013102644Snectar		      krb5_socklen_t *sa_size,
101455682Smarkm		      int port)
101555682Smarkm{
101655682Smarkm    struct addr_operations *a = find_af(af);
101778527Sassar    if (a == NULL) {
1018233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1019233294Sstas				"Address family %d not supported", af);
102055682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
102178527Sassar    }
102255682Smarkm    (*a->h_addr2sockaddr)(addr, sa, sa_size, port);
102355682Smarkm    return 0;
102455682Smarkm}
102555682Smarkm
1026178825Sdfr/**
1027178825Sdfr * krb5_h_addr2addr works like krb5_h_addr2sockaddr with the exception
1028178825Sdfr * that it operates on a krb5_address instead of a struct sockaddr.
1029178825Sdfr *
1030178825Sdfr * @param context a Keberos context
1031178825Sdfr * @param af address family
1032178825Sdfr * @param haddr host address from struct hostent.
1033178825Sdfr * @param addr returned krb5_address.
1034178825Sdfr *
1035178825Sdfr * @return Return an error code or 0.
1036178825Sdfr *
1037178825Sdfr * @ingroup krb5_address
1038178825Sdfr */
1039178825Sdfr
1040233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
104178527Sassarkrb5_h_addr2addr (krb5_context context,
104278527Sassar		  int af,
104355682Smarkm		  const char *haddr, krb5_address *addr)
104455682Smarkm{
104555682Smarkm    struct addr_operations *a = find_af(af);
104678527Sassar    if (a == NULL) {
1047233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1048233294Sstas				N_("Address family %d not supported", ""), af);
104955682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
105078527Sassar    }
105155682Smarkm    return (*a->h_addr2addr)(haddr, addr);
105255682Smarkm}
105355682Smarkm
1054178825Sdfr/**
1055178825Sdfr * krb5_anyaddr fills in a "struct sockaddr sa" that can be used to
1056178825Sdfr * bind(2) to.  The argument sa_size should initially contain the size
1057178825Sdfr * of the sa, and after the call, it will contain the actual length
1058178825Sdfr * of the address.
1059178825Sdfr *
1060178825Sdfr * @param context a Keberos context
1061178825Sdfr * @param af address family
1062178825Sdfr * @param sa sockaddr
1063178825Sdfr * @param sa_size lenght of sa.
1064178825Sdfr * @param port for to fill into sa.
1065178825Sdfr *
1066178825Sdfr * @return Return an error code or 0.
1067178825Sdfr *
1068178825Sdfr * @ingroup krb5_address
1069178825Sdfr */
1070178825Sdfr
1071233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
107278527Sassarkrb5_anyaddr (krb5_context context,
107378527Sassar	      int af,
107455682Smarkm	      struct sockaddr *sa,
1075102644Snectar	      krb5_socklen_t *sa_size,
107655682Smarkm	      int port)
107755682Smarkm{
107855682Smarkm    struct addr_operations *a = find_af (af);
107955682Smarkm
108078527Sassar    if (a == NULL) {
1081233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1082233294Sstas				N_("Address family %d not supported", ""), af);
108355682Smarkm	return KRB5_PROG_ATYPE_NOSUPP;
108478527Sassar    }
108555682Smarkm
108655682Smarkm    (*a->anyaddr)(sa, sa_size, port);
108755682Smarkm    return 0;
108855682Smarkm}
108955682Smarkm
1090178825Sdfr/**
1091178825Sdfr * krb5_print_address prints the address in addr to the string string
1092178825Sdfr * that have the length len. If ret_len is not NULL, it will be filled
1093178825Sdfr * with the length of the string if size were unlimited (not including
1094178825Sdfr * the final NUL) .
1095178825Sdfr *
1096178825Sdfr * @param addr address to be printed
1097178825Sdfr * @param str pointer string to print the address into
1098178825Sdfr * @param len length that will fit into area pointed to by "str".
1099178825Sdfr * @param ret_len return length the str.
1100178825Sdfr *
1101178825Sdfr * @return Return an error code or 0.
1102178825Sdfr *
1103178825Sdfr * @ingroup krb5_address
1104178825Sdfr */
1105178825Sdfr
1106233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1107233294Sstaskrb5_print_address (const krb5_address *addr,
110855682Smarkm		    char *str, size_t len, size_t *ret_len)
110955682Smarkm{
111055682Smarkm    struct addr_operations *a = find_atype(addr->addr_type);
1111178825Sdfr    int ret;
111255682Smarkm
1113120945Snectar    if (a == NULL || a->print_addr == NULL) {
111455682Smarkm	char *s;
111590926Snectar	int l;
1116233294Sstas	size_t i;
111790926Snectar
111855682Smarkm	s = str;
111955682Smarkm	l = snprintf(s, len, "TYPE_%d:", addr->addr_type);
1120233294Sstas	if (l < 0 || (size_t)l >= len)
112190926Snectar	    return EINVAL;
112255682Smarkm	s += l;
112390926Snectar	len -= l;
112455682Smarkm	for(i = 0; i < addr->address.length; i++) {
112555682Smarkm	    l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]);
1126233294Sstas	    if (l < 0 || (size_t)l >= len)
112790926Snectar		return EINVAL;
112855682Smarkm	    len -= l;
112955682Smarkm	    s += l;
113055682Smarkm	}
1131102644Snectar	if(ret_len != NULL)
1132102644Snectar	    *ret_len = s - str;
113355682Smarkm	return 0;
113455682Smarkm    }
1135102644Snectar    ret = (*a->print_addr)(addr, str, len);
1136178825Sdfr    if (ret < 0)
1137178825Sdfr	return EINVAL;
1138102644Snectar    if(ret_len != NULL)
1139102644Snectar	*ret_len = ret;
114055682Smarkm    return 0;
114155682Smarkm}
114255682Smarkm
1143178825Sdfr/**
1144178825Sdfr * krb5_parse_address returns the resolved hostname in string to the
1145178825Sdfr * krb5_addresses addresses .
1146178825Sdfr *
1147178825Sdfr * @param context a Keberos context
1148178825Sdfr * @param string
1149178825Sdfr * @param addresses
1150178825Sdfr *
1151178825Sdfr * @return Return an error code or 0.
1152178825Sdfr *
1153178825Sdfr * @ingroup krb5_address
1154178825Sdfr */
1155178825Sdfr
1156233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
115755682Smarkmkrb5_parse_address(krb5_context context,
115855682Smarkm		   const char *string,
115955682Smarkm		   krb5_addresses *addresses)
116055682Smarkm{
116155682Smarkm    int i, n;
116255682Smarkm    struct addrinfo *ai, *a;
116355682Smarkm    int error;
116478527Sassar    int save_errno;
116555682Smarkm
1166178825Sdfr    addresses->len = 0;
1167178825Sdfr    addresses->val = NULL;
1168178825Sdfr
116955682Smarkm    for(i = 0; i < num_addrs; i++) {
117055682Smarkm	if(at[i].parse_addr) {
1171102644Snectar	    krb5_address addr;
1172102644Snectar	    if((*at[i].parse_addr)(context, string, &addr) == 0) {
117355682Smarkm		ALLOC_SEQ(addresses, 1);
1174178825Sdfr		if (addresses->val == NULL) {
1175233294Sstas		    krb5_set_error_message(context, ENOMEM,
1176233294Sstas					   N_("malloc: out of memory", ""));
1177178825Sdfr		    return ENOMEM;
1178178825Sdfr		}
1179102644Snectar		addresses->val[0] = addr;
118055682Smarkm		return 0;
118155682Smarkm	    }
118255682Smarkm	}
118355682Smarkm    }
118455682Smarkm
118555682Smarkm    error = getaddrinfo (string, NULL, NULL, &ai);
118678527Sassar    if (error) {
1187233294Sstas	krb5_error_code ret2;
118878527Sassar	save_errno = errno;
1189233294Sstas	ret2 = krb5_eai_to_heim_errno(error, save_errno);
1190233294Sstas	krb5_set_error_message (context, ret2, "%s: %s",
1191233294Sstas				string, gai_strerror(error));
1192233294Sstas	return ret2;
119378527Sassar    }
1194233294Sstas
119555682Smarkm    n = 0;
119655682Smarkm    for (a = ai; a != NULL; a = a->ai_next)
119755682Smarkm	++n;
119855682Smarkm
119955682Smarkm    ALLOC_SEQ(addresses, n);
1200178825Sdfr    if (addresses->val == NULL) {
1201233294Sstas	krb5_set_error_message(context, ENOMEM,
1202233294Sstas			       N_("malloc: out of memory", ""));
1203178825Sdfr	freeaddrinfo(ai);
1204178825Sdfr	return ENOMEM;
1205178825Sdfr    }
120655682Smarkm
1207178825Sdfr    addresses->len = 0;
1208102644Snectar    for (a = ai, i = 0; a != NULL; a = a->ai_next) {
1209178825Sdfr	if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i]))
1210178825Sdfr	    continue;
1211233294Sstas	if(krb5_address_search(context, &addresses->val[i], addresses)) {
1212233294Sstas	    krb5_free_address(context, &addresses->val[i]);
1213178825Sdfr	    continue;
1214233294Sstas	}
1215233294Sstas	i++;
1216178825Sdfr	addresses->len = i;
121755682Smarkm    }
121855682Smarkm    freeaddrinfo (ai);
121955682Smarkm    return 0;
122055682Smarkm}
122190926Snectar
1222178825Sdfr/**
1223178825Sdfr * krb5_address_order compares the addresses addr1 and addr2 so that
1224178825Sdfr * it can be used for sorting addresses. If the addresses are the same
1225233294Sstas * address krb5_address_order will return 0. Behavies like memcmp(2).
1226178825Sdfr *
1227178825Sdfr * @param context a Keberos context
1228178825Sdfr * @param addr1 krb5_address to compare
1229178825Sdfr * @param addr2 krb5_address to compare
1230178825Sdfr *
1231178825Sdfr * @return < 0 if address addr1 in "less" then addr2. 0 if addr1 and
1232178825Sdfr * addr2 is the same address, > 0 if addr2 is "less" then addr1.
1233178825Sdfr *
1234178825Sdfr * @ingroup krb5_address
1235178825Sdfr */
1236178825Sdfr
1237233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
123890926Snectarkrb5_address_order(krb5_context context,
123990926Snectar		   const krb5_address *addr1,
124090926Snectar		   const krb5_address *addr2)
124190926Snectar{
124290926Snectar    /* this sucks; what if both addresses have order functions, which
124390926Snectar       should we call? this works for now, though */
124490926Snectar    struct addr_operations *a;
1245233294Sstas    a = find_atype(addr1->addr_type);
124690926Snectar    if(a == NULL) {
1247233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1248233294Sstas				N_("Address family %d not supported", ""),
1249233294Sstas				addr1->addr_type);
125090926Snectar	return KRB5_PROG_ATYPE_NOSUPP;
125190926Snectar    }
1252233294Sstas    if(a->order_addr != NULL)
1253233294Sstas	return (*a->order_addr)(context, addr1, addr2);
1254233294Sstas    a = find_atype(addr2->addr_type);
125590926Snectar    if(a == NULL) {
1256233294Sstas	krb5_set_error_message (context, KRB5_PROG_ATYPE_NOSUPP,
1257233294Sstas				N_("Address family %d not supported", ""),
1258233294Sstas				addr2->addr_type);
125990926Snectar	return KRB5_PROG_ATYPE_NOSUPP;
126090926Snectar    }
1261233294Sstas    if(a->order_addr != NULL)
126290926Snectar	return (*a->order_addr)(context, addr1, addr2);
126390926Snectar
126490926Snectar    if(addr1->addr_type != addr2->addr_type)
126590926Snectar	return addr1->addr_type - addr2->addr_type;
126690926Snectar    if(addr1->address.length != addr2->address.length)
126790926Snectar	return addr1->address.length - addr2->address.length;
126890926Snectar    return memcmp (addr1->address.data,
126990926Snectar		   addr2->address.data,
127090926Snectar		   addr1->address.length);
127190926Snectar}
127290926Snectar
1273178825Sdfr/**
1274178825Sdfr * krb5_address_compare compares the addresses  addr1 and addr2.
1275178825Sdfr * Returns TRUE if the two addresses are the same.
1276178825Sdfr *
1277178825Sdfr * @param context a Keberos context
1278178825Sdfr * @param addr1 address to compare
1279178825Sdfr * @param addr2 address to compare
1280178825Sdfr *
1281178825Sdfr * @return Return an TRUE is the address are the same FALSE if not
1282178825Sdfr *
1283178825Sdfr * @ingroup krb5_address
1284178825Sdfr */
1285178825Sdfr
1286233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
128790926Snectarkrb5_address_compare(krb5_context context,
128890926Snectar		     const krb5_address *addr1,
128990926Snectar		     const krb5_address *addr2)
129090926Snectar{
129190926Snectar    return krb5_address_order (context, addr1, addr2) == 0;
129290926Snectar}
129390926Snectar
1294178825Sdfr/**
1295178825Sdfr * krb5_address_search checks if the address addr is a member of the
1296178825Sdfr * address set list addrlist .
1297178825Sdfr *
1298178825Sdfr * @param context a Keberos context.
1299178825Sdfr * @param addr address to search for.
1300178825Sdfr * @param addrlist list of addresses to look in for addr.
1301178825Sdfr *
1302178825Sdfr * @return Return an error code or 0.
1303178825Sdfr *
1304178825Sdfr * @ingroup krb5_address
1305178825Sdfr */
1306178825Sdfr
1307233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
130890926Snectarkrb5_address_search(krb5_context context,
130990926Snectar		    const krb5_address *addr,
131090926Snectar		    const krb5_addresses *addrlist)
131190926Snectar{
1312233294Sstas    size_t i;
131390926Snectar
131490926Snectar    for (i = 0; i < addrlist->len; ++i)
131590926Snectar	if (krb5_address_compare (context, addr, &addrlist->val[i]))
131690926Snectar	    return TRUE;
131790926Snectar    return FALSE;
131890926Snectar}
131990926Snectar
1320178825Sdfr/**
1321178825Sdfr * krb5_free_address frees the data stored in the address that is
1322178825Sdfr * alloced with any of the krb5_address functions.
1323178825Sdfr *
1324178825Sdfr * @param context a Keberos context
1325178825Sdfr * @param address addresss to be freed.
1326178825Sdfr *
1327178825Sdfr * @return Return an error code or 0.
1328178825Sdfr *
1329178825Sdfr * @ingroup krb5_address
1330178825Sdfr */
1331178825Sdfr
1332233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
133390926Snectarkrb5_free_address(krb5_context context,
133490926Snectar		  krb5_address *address)
133590926Snectar{
1336178825Sdfr    struct addr_operations *a = find_atype (address->addr_type);
133790926Snectar    if(a != NULL && a->free_addr != NULL)
133890926Snectar	return (*a->free_addr)(context, address);
133990926Snectar    krb5_data_free (&address->address);
1340178825Sdfr    memset(address, 0, sizeof(*address));
134190926Snectar    return 0;
134290926Snectar}
134390926Snectar
1344178825Sdfr/**
1345178825Sdfr * krb5_free_addresses frees the data stored in the address that is
1346178825Sdfr * alloced with any of the krb5_address functions.
1347178825Sdfr *
1348178825Sdfr * @param context a Keberos context
1349178825Sdfr * @param addresses addressses to be freed.
1350178825Sdfr *
1351178825Sdfr * @return Return an error code or 0.
1352178825Sdfr *
1353178825Sdfr * @ingroup krb5_address
1354178825Sdfr */
1355178825Sdfr
1356233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
135790926Snectarkrb5_free_addresses(krb5_context context,
135890926Snectar		    krb5_addresses *addresses)
135990926Snectar{
1360233294Sstas    size_t i;
136190926Snectar    for(i = 0; i < addresses->len; i++)
136290926Snectar	krb5_free_address(context, &addresses->val[i]);
136390926Snectar    free(addresses->val);
1364178825Sdfr    addresses->len = 0;
1365178825Sdfr    addresses->val = NULL;
136690926Snectar    return 0;
136790926Snectar}
136890926Snectar
1369178825Sdfr/**
1370178825Sdfr * krb5_copy_address copies the content of address
1371178825Sdfr * inaddr to outaddr.
1372178825Sdfr *
1373178825Sdfr * @param context a Keberos context
1374178825Sdfr * @param inaddr pointer to source address
1375178825Sdfr * @param outaddr pointer to destination address
1376178825Sdfr *
1377178825Sdfr * @return Return an error code or 0.
1378178825Sdfr *
1379178825Sdfr * @ingroup krb5_address
1380178825Sdfr */
1381178825Sdfr
1382233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
138390926Snectarkrb5_copy_address(krb5_context context,
138490926Snectar		  const krb5_address *inaddr,
138590926Snectar		  krb5_address *outaddr)
138690926Snectar{
138790926Snectar    struct addr_operations *a = find_af (inaddr->addr_type);
138890926Snectar    if(a != NULL && a->copy_addr != NULL)
138990926Snectar	return (*a->copy_addr)(context, inaddr, outaddr);
139090926Snectar    return copy_HostAddress(inaddr, outaddr);
139190926Snectar}
139290926Snectar
1393178825Sdfr/**
1394178825Sdfr * krb5_copy_addresses copies the content of addresses
1395178825Sdfr * inaddr to outaddr.
1396178825Sdfr *
1397178825Sdfr * @param context a Keberos context
1398178825Sdfr * @param inaddr pointer to source addresses
1399178825Sdfr * @param outaddr pointer to destination addresses
1400178825Sdfr *
1401178825Sdfr * @return Return an error code or 0.
1402178825Sdfr *
1403178825Sdfr * @ingroup krb5_address
1404178825Sdfr */
1405178825Sdfr
1406233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
140790926Snectarkrb5_copy_addresses(krb5_context context,
140890926Snectar		    const krb5_addresses *inaddr,
140990926Snectar		    krb5_addresses *outaddr)
141090926Snectar{
1411233294Sstas    size_t i;
141290926Snectar    ALLOC_SEQ(outaddr, inaddr->len);
141390926Snectar    if(inaddr->len > 0 && outaddr->val == NULL)
141490926Snectar	return ENOMEM;
141590926Snectar    for(i = 0; i < inaddr->len; i++)
141690926Snectar	krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]);
141790926Snectar    return 0;
141890926Snectar}
141990926Snectar
1420178825Sdfr/**
1421178825Sdfr * krb5_append_addresses adds the set of addresses in source to
1422178825Sdfr * dest. While copying the addresses, duplicates are also sorted out.
1423178825Sdfr *
1424178825Sdfr * @param context a Keberos context
1425178825Sdfr * @param dest destination of copy operation
1426178825Sdfr * @param source adresses that are going to be added to dest
1427178825Sdfr *
1428178825Sdfr * @return Return an error code or 0.
1429178825Sdfr *
1430178825Sdfr * @ingroup krb5_address
1431178825Sdfr */
1432178825Sdfr
1433233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
143490926Snectarkrb5_append_addresses(krb5_context context,
143590926Snectar		      krb5_addresses *dest,
143690926Snectar		      const krb5_addresses *source)
143790926Snectar{
143890926Snectar    krb5_address *tmp;
143990926Snectar    krb5_error_code ret;
1440233294Sstas    size_t i;
144190926Snectar    if(source->len > 0) {
144290926Snectar	tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp));
144390926Snectar	if(tmp == NULL) {
1444233294Sstas	    krb5_set_error_message (context, ENOMEM,
1445233294Sstas				    N_("malloc: out of memory", ""));
144690926Snectar	    return ENOMEM;
144790926Snectar	}
144890926Snectar	dest->val = tmp;
144990926Snectar	for(i = 0; i < source->len; i++) {
145090926Snectar	    /* skip duplicates */
145190926Snectar	    if(krb5_address_search(context, &source->val[i], dest))
145290926Snectar		continue;
1453233294Sstas	    ret = krb5_copy_address(context,
1454233294Sstas				    &source->val[i],
145590926Snectar				    &dest->val[dest->len]);
145690926Snectar	    if(ret)
145790926Snectar		return ret;
145890926Snectar	    dest->len++;
145990926Snectar	}
146090926Snectar    }
146190926Snectar    return 0;
146290926Snectar}
146390926Snectar
1464178825Sdfr/**
146590926Snectar * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port)
1466178825Sdfr *
1467178825Sdfr * @param context a Keberos context
1468178825Sdfr * @param res built address from addr/port
1469178825Sdfr * @param addr address to use
1470178825Sdfr * @param port port to use
1471178825Sdfr *
1472178825Sdfr * @return Return an error code or 0.
1473178825Sdfr *
1474178825Sdfr * @ingroup krb5_address
147590926Snectar */
147690926Snectar
1477233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
147890926Snectarkrb5_make_addrport (krb5_context context,
147990926Snectar		    krb5_address **res, const krb5_address *addr, int16_t port)
148090926Snectar{
148190926Snectar    krb5_error_code ret;
148290926Snectar    size_t len = addr->address.length + 2 + 4 * 4;
148390926Snectar    u_char *p;
148490926Snectar
148590926Snectar    *res = malloc (sizeof(**res));
148690926Snectar    if (*res == NULL) {
1487233294Sstas	krb5_set_error_message (context, ENOMEM,
1488233294Sstas				N_("malloc: out of memory", ""));
148990926Snectar	return ENOMEM;
149090926Snectar    }
149190926Snectar    (*res)->addr_type = KRB5_ADDRESS_ADDRPORT;
149290926Snectar    ret = krb5_data_alloc (&(*res)->address, len);
149390926Snectar    if (ret) {
1494233294Sstas	krb5_set_error_message (context, ret,
1495233294Sstas				N_("malloc: out of memory", ""));
149690926Snectar	free (*res);
1497178825Sdfr	*res = NULL;
149890926Snectar	return ret;
149990926Snectar    }
150090926Snectar    p = (*res)->address.data;
150190926Snectar    *p++ = 0;
150290926Snectar    *p++ = 0;
150390926Snectar    *p++ = (addr->addr_type     ) & 0xFF;
150490926Snectar    *p++ = (addr->addr_type >> 8) & 0xFF;
150590926Snectar
150690926Snectar    *p++ = (addr->address.length      ) & 0xFF;
150790926Snectar    *p++ = (addr->address.length >>  8) & 0xFF;
150890926Snectar    *p++ = (addr->address.length >> 16) & 0xFF;
150990926Snectar    *p++ = (addr->address.length >> 24) & 0xFF;
151090926Snectar
151190926Snectar    memcpy (p, addr->address.data, addr->address.length);
151290926Snectar    p += addr->address.length;
151390926Snectar
151490926Snectar    *p++ = 0;
151590926Snectar    *p++ = 0;
151690926Snectar    *p++ = (KRB5_ADDRESS_IPPORT     ) & 0xFF;
151790926Snectar    *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF;
151890926Snectar
151990926Snectar    *p++ = (2      ) & 0xFF;
152090926Snectar    *p++ = (2 >>  8) & 0xFF;
152190926Snectar    *p++ = (2 >> 16) & 0xFF;
152290926Snectar    *p++ = (2 >> 24) & 0xFF;
152390926Snectar
152490926Snectar    memcpy (p, &port, 2);
152590926Snectar
152690926Snectar    return 0;
152790926Snectar}
1528178825Sdfr
1529178825Sdfr/**
1530178825Sdfr * Calculate the boundary addresses of `inaddr'/`prefixlen' and store
1531178825Sdfr * them in `low' and `high'.
1532178825Sdfr *
1533178825Sdfr * @param context a Keberos context
1534178825Sdfr * @param inaddr address in prefixlen that the bondery searched
1535178825Sdfr * @param prefixlen width of boundery
1536178825Sdfr * @param low lowest address
1537178825Sdfr * @param high highest address
1538178825Sdfr *
1539178825Sdfr * @return Return an error code or 0.
1540178825Sdfr *
1541178825Sdfr * @ingroup krb5_address
1542178825Sdfr */
1543178825Sdfr
1544233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1545178825Sdfrkrb5_address_prefixlen_boundary(krb5_context context,
1546178825Sdfr				const krb5_address *inaddr,
1547178825Sdfr				unsigned long prefixlen,
1548178825Sdfr				krb5_address *low,
1549178825Sdfr				krb5_address *high)
1550178825Sdfr{
1551178825Sdfr    struct addr_operations *a = find_atype (inaddr->addr_type);
1552178825Sdfr    if(a != NULL && a->mask_boundary != NULL)
1553178825Sdfr	return (*a->mask_boundary)(context, inaddr, prefixlen, low, high);
1554233294Sstas    krb5_set_error_message(context, KRB5_PROG_ATYPE_NOSUPP,
1555233294Sstas			   N_("Address family %d doesn't support "
1556233294Sstas			      "address mask operation", ""),
1557233294Sstas			   inaddr->addr_type);
1558178825Sdfr    return KRB5_PROG_ATYPE_NOSUPP;
1559178825Sdfr}
1560