From abc905d3c9e814af99c88591969332e1cd584472 Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Mon, 2 Jul 2001 22:26:42 +0000 Subject: [PATCH] add new `arange' fake address type, that matches more than one address; this required some internal changes to many functions, so all of address.c got moved here (wasn't much left there) git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10237 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/krb5/addr_families.c | 353 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 348 insertions(+), 5 deletions(-) diff --git a/lib/krb5/addr_families.c b/lib/krb5/addr_families.c index c5cc07993..d78865b8d 100644 --- a/lib/krb5/addr_families.c +++ b/lib/krb5/addr_families.c @@ -48,7 +48,10 @@ struct addr_operations { krb5_boolean (*uninteresting)(const struct sockaddr *); void (*anyaddr)(struct sockaddr *, int *, int); int (*print_addr)(const krb5_address *, char *, size_t); - int (*parse_addr)(const char*, krb5_address *); + int (*parse_addr)(krb5_context, const char*, krb5_address *); + int (*order_addr)(krb5_context, const krb5_address*, const krb5_address*); + int (*free_addr)(krb5_context, krb5_address*); + int (*copy_addr)(krb5_context, const krb5_address*, krb5_address*); }; /* @@ -152,7 +155,7 @@ ipv4_print_addr (const krb5_address *addr, char *str, size_t len) } static int -ipv4_parse_addr (const char *address, krb5_address *addr) +ipv4_parse_addr (krb5_context context, const char *address, krb5_address *addr) { const char *p; struct in_addr a; @@ -313,10 +316,20 @@ ipv6_print_addr (const krb5_address *addr, char *str, size_t len) } static int -ipv6_parse_addr (const char *address, krb5_address *addr) +ipv6_parse_addr (krb5_context context, const char *address, krb5_address *addr) { int ret; struct in6_addr in6; + const char *p; + + p = strchr(address, ':'); + if(p) { + p++; + if(strncasecmp(address, "ip6:", p - address) == 0 || + strncasecmp(address, "ipv6:", p - address) == 0 || + strncasecmp(address, "inet6:", p - address) == 0) + address = p; + } ret = inet_pton(AF_INET6, address, &in6.s6_addr); if(ret == 1) { @@ -336,6 +349,152 @@ ipv6_parse_addr (const char *address, krb5_address *addr) * table */ +#define AF_ARANGE (-100) +#define KRB5_ADDRESS_ARANGE AF_ARANGE + +struct arange { + krb5_address low; + krb5_address high; +}; + +static int +arange_parse_addr (krb5_context context, + const char *address, krb5_address *addr) +{ + char buf[1024]; + krb5_addresses low, high; + struct arange *a; + krb5_error_code ret; + + if(strncasecmp(address, "RANGE:", 6) != 0) + return -1; + + address += 6; + + /* should handle netmasks */ + strsep_copy(&address, "-", buf, sizeof(buf)); + ret = krb5_parse_address(context, buf, &low); + if(ret) + return ret; + if(low.len != 1) { + krb5_free_addresses(context, &low); + return -1; + } + + strsep_copy(&address, "-", buf, sizeof(buf)); + ret = krb5_parse_address(context, buf, &high); + if(ret) { + krb5_free_addresses(context, &low); + return ret; + } + + if(high.len != 1 || high.val[0].addr_type != low.val[0].addr_type) { + krb5_free_addresses(context, &low); + krb5_free_addresses(context, &high); + return -1; + } + + krb5_data_alloc(&addr->address, sizeof(*a)); + addr->addr_type = KRB5_ADDRESS_ARANGE; + a = addr->address.data; + + if(krb5_address_order(context, &low.val[0], &high.val[0]) < 0) { + a->low = low.val[0]; + a->high = high.val[0]; + } else { + a->low = high.val[0]; + a->high = low.val[0]; + } + return 0; +} + +static int +arange_free (krb5_context context, krb5_address *addr) +{ + struct arange *a; + a = addr->address.data; + krb5_free_address(context, &a->low); + krb5_free_address(context, &a->high); + return 0; +} + + +static int +arange_copy (krb5_context context, const krb5_address *inaddr, + krb5_address *outaddr) +{ + struct arange *i, *o; + copy_HostAddress(inaddr, outaddr); + i = inaddr->address.data; + o = outaddr->address.data; + krb5_copy_address(context, &i->low, &o->low); + krb5_copy_address(context, &i->high, &o->high); + return 0; +} + +static int +arange_print_addr (const krb5_address *addr, char *str, size_t len) +{ + struct arange *a; + krb5_error_code ret; + size_t l, ret_len = 0; + + a = addr->address.data; + + l = strlcpy(str, "RANGE:", len); + ret_len += l; + + ret = krb5_print_address (&a->low, str + ret_len, len - ret_len, &l); + ret_len += l; + + l = strlcat(str, "-", len); + ret_len += l; + + ret = krb5_print_address (&a->high, str + ret_len, len - ret_len, &l); + ret_len += l; + + return ret_len; +} + +static int +arange_order_addr(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + int tmp1, tmp2, sign; + struct arange *a; + const krb5_address *a2; + + if(addr1->addr_type == KRB5_ADDRESS_ARANGE) { + a = addr1->address.data; + a2 = addr2; + sign = 1; + } else if(addr2->addr_type == KRB5_ADDRESS_ARANGE) { + a = addr2->address.data; + a2 = addr1; + sign = -1; + } else + abort(); + + if(a2->addr_type == KRB5_ADDRESS_ARANGE) { + struct arange *b = a2->address.data; + tmp1 = krb5_address_order(context, &a->low, &b->low); + if(tmp1 != 0) + return sign * tmp1; + return sign * krb5_address_order(context, &a->high, &b->high); + } else if(a2->addr_type == a->low.addr_type) { + tmp1 = krb5_address_order(context, &a->low, a2); + if(tmp1 > 0) + return sign; + tmp2 = krb5_address_order(context, &a->high, a2); + if(tmp2 < 0) + return -sign; + return 0; + } else { + return sign * (addr1->addr_type - addr2->addr_type); + } +} + static struct addr_operations at[] = { {AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), ipv4_sockaddr2addr, @@ -351,8 +510,13 @@ static struct addr_operations at[] = { ipv6_addr2sockaddr, ipv6_h_addr2sockaddr, ipv6_h_addr2addr, - ipv6_uninteresting, ipv6_anyaddr, ipv6_print_addr, ipv6_parse_addr} + ipv6_uninteresting, ipv6_anyaddr, ipv6_print_addr, ipv6_parse_addr} , #endif + /* fake address type */ + {AF_ARANGE, KRB5_ADDRESS_ARANGE, sizeof(struct arange), + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + arange_print_addr, arange_parse_addr, + arange_order_addr, arange_free, arange_copy } }; static int num_addrs = sizeof(at) / sizeof(at[0]); @@ -425,6 +589,11 @@ krb5_addr2sockaddr (krb5_context context, addr->addr_type); return KRB5_PROG_ATYPE_NOSUPP; } + if (a->addr2sockaddr == NULL) { + krb5_set_error_string (context, "Can't convert address type %d to sockaddr", + addr->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } (*a->addr2sockaddr)(addr, sa, sa_size, port); return 0; } @@ -535,7 +704,7 @@ krb5_parse_address(krb5_context context, for(i = 0; i < num_addrs; i++) { if(at[i].parse_addr) { krb5_address a; - if((*at[i].parse_addr)(string, &a) == 0) { + if((*at[i].parse_addr)(context, string, &a) == 0) { ALLOC_SEQ(addresses, 1); addresses->val[0] = a; return 0; @@ -562,3 +731,177 @@ krb5_parse_address(krb5_context context, freeaddrinfo (ai); return 0; } + +int +krb5_address_order(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + /* this sucks; what if both addresses have order functions, which + should we call? this works for now, though */ + struct addr_operations *a; + a = find_atype(addr1->addr_type); + if(a->order_addr != NULL) + return (*a->order_addr)(context, addr1, addr2); + a = find_atype(addr2->addr_type); + if(a->order_addr != NULL) + return (*a->order_addr)(context, addr1, addr2); + + if(addr1->addr_type != addr2->addr_type) + return addr1->addr_type - addr2->addr_type; + return memcmp (addr1->address.data, + addr2->address.data, + addr1->address.length); +} + +krb5_boolean +krb5_address_compare(krb5_context context, + const krb5_address *addr1, + const krb5_address *addr2) +{ + return krb5_address_order (context, addr1, addr2) == 0; +} + +krb5_boolean +krb5_address_search(krb5_context context, + const krb5_address *addr, + const krb5_addresses *addrlist) +{ + int i; + + for (i = 0; i < addrlist->len; ++i) + if (krb5_address_compare (context, addr, &addrlist->val[i])) + return TRUE; + return FALSE; +} + +krb5_error_code +krb5_free_address(krb5_context context, + krb5_address *address) +{ + struct addr_operations *a = find_af (address->addr_type); + if(a != NULL && a->free_addr != NULL) + return (*a->free_addr)(context, address); + krb5_data_free (&address->address); + return 0; +} + +krb5_error_code +krb5_free_addresses(krb5_context context, + krb5_addresses *addresses) +{ + int i; + for(i = 0; i < addresses->len; i++) + krb5_free_address(context, &addresses->val[i]); + free(addresses->val); + return 0; +} + +krb5_error_code +krb5_copy_address(krb5_context context, + const krb5_address *inaddr, + krb5_address *outaddr) +{ + struct addr_operations *a = find_af (inaddr->addr_type); + if(a != NULL && a->copy_addr != NULL) + return (*a->copy_addr)(context, inaddr, outaddr); + return copy_HostAddress(inaddr, outaddr); +} + +krb5_error_code +krb5_copy_addresses(krb5_context context, + const krb5_addresses *inaddr, + krb5_addresses *outaddr) +{ + int i; + ALLOC_SEQ(outaddr, inaddr->len); + if(inaddr->len > 0 && outaddr->val == NULL) + return ENOMEM; + for(i = 0; i < inaddr->len; i++) + krb5_copy_address(context, &inaddr->val[i], &outaddr->val[i]); + return 0; +} + +krb5_error_code +krb5_append_addresses(krb5_context context, + krb5_addresses *dest, + const krb5_addresses *source) +{ + krb5_address *tmp; + krb5_error_code ret; + int i; + if(source->len > 0) { + tmp = realloc(dest->val, (dest->len + source->len) * sizeof(*tmp)); + if(tmp == NULL) { + krb5_set_error_string(context, "realloc: out of memory"); + return ENOMEM; + } + dest->val = tmp; + for(i = 0; i < source->len; i++) { + /* skip duplicates */ + if(krb5_address_search(context, &source->val[i], dest)) + continue; + ret = krb5_copy_address(context, + &source->val[i], + &dest->val[dest->len]); + if(ret) + return ret; + dest->len++; + } + } + return 0; +} + +/* + * Create an address of type KRB5_ADDRESS_ADDRPORT from (addr, port) + */ + +krb5_error_code +krb5_make_addrport (krb5_context context, + krb5_address **res, const krb5_address *addr, int16_t port) +{ + krb5_error_code ret; + size_t len = addr->address.length + 2 + 4 * 4; + u_char *p; + + *res = malloc (sizeof(**res)); + if (*res == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); + return ENOMEM; + } + (*res)->addr_type = KRB5_ADDRESS_ADDRPORT; + ret = krb5_data_alloc (&(*res)->address, len); + if (ret) { + krb5_set_error_string(context, "malloc: out of memory"); + free (*res); + return ret; + } + p = (*res)->address.data; + *p++ = 0; + *p++ = 0; + *p++ = (addr->addr_type ) & 0xFF; + *p++ = (addr->addr_type >> 8) & 0xFF; + + *p++ = (addr->address.length ) & 0xFF; + *p++ = (addr->address.length >> 8) & 0xFF; + *p++ = (addr->address.length >> 16) & 0xFF; + *p++ = (addr->address.length >> 24) & 0xFF; + + memcpy (p, addr->address.data, addr->address.length); + p += addr->address.length; + + *p++ = 0; + *p++ = 0; + *p++ = (KRB5_ADDRESS_IPPORT ) & 0xFF; + *p++ = (KRB5_ADDRESS_IPPORT >> 8) & 0xFF; + + *p++ = (2 ) & 0xFF; + *p++ = (2 >> 8) & 0xFF; + *p++ = (2 >> 16) & 0xFF; + *p++ = (2 >> 24) & 0xFF; + + memcpy (p, &port, 2); + p += 2; + + return 0; +}