diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2005-04-20 20:28:55 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2005-04-20 20:28:55 +0000 |
commit | 81f181d604d7310280878c440cccb92f30db532a (patch) | |
tree | 3a66fbbe5a8adfe76e76ef0e801847054c593396 | |
parent | 0133950253919ad3f20cba87a9b2c82dcfaf2692 (diff) |
fix snprintf and strlcpy abuse, returning the string length is at least
save in the case where this is being used in pointer arithmatic
ok cloder@
-rw-r--r-- | kerberosV/src/lib/krb5/addr_families.c | 667 | ||||
-rw-r--r-- | kerberosV/src/lib/krb5/get_host_realm.c | 74 |
2 files changed, 614 insertions, 127 deletions
diff --git a/kerberosV/src/lib/krb5/addr_families.c b/kerberosV/src/lib/krb5/addr_families.c index 2d5d265b67f..5354f33ec39 100644 --- a/kerberosV/src/lib/krb5/addr_families.c +++ b/kerberosV/src/lib/krb5/addr_families.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-1999 Kungliga Tekniska H�gskolan + * Copyright (c) 1997-2003 Kungliga Tekniska H�gskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$KTH: addr_families.c,v 1.24 2000/07/08 13:05:43 joda Exp $"); +RCSID("$KTH: addr_families.c,v 1.38 2003/03/25 12:37:02 joda Exp $"); struct addr_operations { int af; @@ -42,13 +42,16 @@ struct addr_operations { krb5_error_code (*sockaddr2addr)(const struct sockaddr *, krb5_address *); krb5_error_code (*sockaddr2port)(const struct sockaddr *, int16_t *); void (*addr2sockaddr)(const krb5_address *, struct sockaddr *, - int *sa_size, int port); - void (*h_addr2sockaddr)(const char *, struct sockaddr *, int *, int); + krb5_socklen_t *sa_size, int port); + void (*h_addr2sockaddr)(const char *, struct sockaddr *, krb5_socklen_t *, int); krb5_error_code (*h_addr2addr)(const char *, krb5_address *); krb5_boolean (*uninteresting)(const struct sockaddr *); - void (*anyaddr)(struct sockaddr *, int *, int); + void (*anyaddr)(struct sockaddr *, krb5_socklen_t *, 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*); }; /* @@ -78,29 +81,33 @@ ipv4_sockaddr2port (const struct sockaddr *sa, int16_t *port) static void ipv4_addr2sockaddr (const krb5_address *a, struct sockaddr *sa, - int *sa_size, + krb5_socklen_t *sa_size, int port) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - memset (sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - memcpy (&sin->sin_addr, a->address.data, 4); - sin->sin_port = port; - *sa_size = sizeof(*sin); + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + memcpy (&tmp.sin_addr, a->address.data, 4); + tmp.sin_port = port; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); } static void ipv4_h_addr2sockaddr(const char *addr, - struct sockaddr *sa, int *sa_size, int port) + struct sockaddr *sa, + krb5_socklen_t *sa_size, + int port) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - memset (sin, 0, sizeof(*sin)); - *sa_size = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = port; - sin->sin_addr = *((const struct in_addr *)addr); + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + tmp.sin_port = port; + tmp.sin_addr = *((const struct in_addr *)addr); + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); } static krb5_error_code @@ -130,15 +137,16 @@ ipv4_uninteresting (const struct sockaddr *sa) } static void -ipv4_anyaddr (struct sockaddr *sa, int *sa_size, int port) +ipv4_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - - memset (sin, 0, sizeof(*sin)); - *sa_size = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = port; - sin->sin_addr.s_addr = INADDR_ANY; + struct sockaddr_in tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin_family = AF_INET; + tmp.sin_port = port; + tmp.sin_addr.s_addr = INADDR_ANY; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); } static int @@ -146,13 +154,17 @@ ipv4_print_addr (const krb5_address *addr, char *str, size_t len) { struct in_addr ia; + if (len == 0) + return(0); + memcpy (&ia, addr->address.data, 4); - return snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); + (void) snprintf (str, len, "IPv4:%s", inet_ntoa(ia)); + return(strlen(str)); } 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; @@ -228,31 +240,33 @@ ipv6_sockaddr2port (const struct sockaddr *sa, int16_t *port) static void ipv6_addr2sockaddr (const krb5_address *a, struct sockaddr *sa, - int *sa_size, + krb5_socklen_t *sa_size, int port) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - memset (sin6, 0, sizeof(*sin6)); - sin6->sin6_family = AF_INET6; - memcpy (&sin6->sin6_addr, a->address.data, sizeof(sin6->sin6_addr)); - sin6->sin6_port = port; - *sa_size = sizeof(*sin6); + struct sockaddr_in6 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + memcpy (&tmp.sin6_addr, a->address.data, sizeof(tmp.sin6_addr)); + tmp.sin6_port = port; + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); } static void ipv6_h_addr2sockaddr(const char *addr, struct sockaddr *sa, - int *sa_size, + krb5_socklen_t *sa_size, int port) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; - - memset (sin6, 0, sizeof(*sin6)); - *sa_size = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = port; - sin6->sin6_addr = *((const struct in6_addr *)addr); + struct sockaddr_in6 tmp; + + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + tmp.sin6_port = port; + tmp.sin6_addr = *((const struct in6_addr *)addr); + memcpy(sa, &tmp, min(sizeof(tmp), *sa_size)); + *sa_size = sizeof(tmp); } static krb5_error_code @@ -279,44 +293,44 @@ ipv6_uninteresting (const struct sockaddr *sa) } static void -ipv6_anyaddr (struct sockaddr *sa, int *sa_size, int port) +ipv6_anyaddr (struct sockaddr *sa, krb5_socklen_t *sa_size, int port) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + struct sockaddr_in6 tmp; - memset (sin6, 0, sizeof(*sin6)); - *sa_size = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = port; - sin6->sin6_addr = in6addr_any; + memset (&tmp, 0, sizeof(tmp)); + tmp.sin6_family = AF_INET6; + tmp.sin6_port = port; + tmp.sin6_addr = in6addr_any; + *sa_size = sizeof(tmp); } static int ipv6_print_addr (const krb5_address *addr, char *str, size_t len) { - char buf[128], buf2[3]; -#ifdef HAVE_INET_NTOP + char buf[128]; if(inet_ntop(AF_INET6, addr->address.data, buf, sizeof(buf)) == NULL) -#endif - { - /* XXX this is pretty ugly, but better than abort() */ - int i; - unsigned char *p = addr->address.data; - buf[0] = '\0'; - for(i = 0; i < addr->address.length; i++) { - snprintf(buf2, sizeof(buf2), "%02x", p[i]); - if(i > 0 && (i & 1) == 0) - strlcat(buf, ":", sizeof(buf)); - strlcat(buf, buf2, sizeof(buf)); - } - } - return snprintf(str, len, "IPv6:%s", buf); + return (0); + if (len == 0) + return(0); + (void) snprintf(str, len, "IPv6:%s", buf); + return(strlen(str)); } 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 +350,200 @@ ipv6_parse_addr (const char *address, krb5_address *addr) * table */ +#define KRB5_ADDRESS_ARANGE (-100) + +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) +{ + krb5_error_code ret; + struct arange *i, *o; + + outaddr->addr_type = KRB5_ADDRESS_ARANGE; + ret = krb5_data_alloc(&outaddr->address, sizeof(*o)); + if(ret) + return ret; + i = inaddr->address.data; + o = outaddr->address.data; + ret = krb5_copy_address(context, &i->low, &o->low); + if(ret) { + krb5_data_free(&outaddr->address); + return ret; + } + ret = krb5_copy_address(context, &i->high, &o->high); + if(ret) { + krb5_free_address(context, &o->low); + krb5_data_free(&outaddr->address); + return ret; + } + 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; + + if (len == 0) + return(0); + + a = addr->address.data; + + (void) strlcpy(str, "RANGE:", len); + ret_len += strlen(str); /* truncate if too long */ + + ret = krb5_print_address (&a->low, str + ret_len, len - ret_len, &l); + ret_len += l; + + (void) strlcat(str, "-", len); + ret_len += strlen(str); /* truncate if too long */ + + 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 int +addrport_print_addr (const krb5_address *addr, char *str, size_t len) +{ + krb5_address addr1, addr2; + uint16_t port = 0; + size_t ret_len = 0, l; + krb5_storage *sp = krb5_storage_from_data((krb5_data*)&addr->address); + /* for totally obscure reasons, these are not in network byteorder */ + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); + + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip first two bytes */ + krb5_ret_address(sp, &addr1); + + krb5_storage_seek(sp, 2, SEEK_CUR); /* skip two bytes */ + krb5_ret_address(sp, &addr2); + krb5_storage_free(sp); + if(addr2.addr_type == KRB5_ADDRESS_IPPORT && addr2.address.length == 2) { + unsigned long value; + _krb5_get_int(addr2.address.data, &value, 2); + port = value; + } + l = strlcpy(str, "ADDRPORT:", len); + ret_len += strlen(str); /* truncate if too long */ + krb5_print_address(&addr1, str + ret_len, len - ret_len, &l); + ret_len += l; + /* XXX oh the horror */ + if ((len - ret_len) == 0) + return(ret_len); + (void) snprintf(str + ret_len, len - ret_len, ",PORT=%u", port); + return(strlen(str)); +} + static struct addr_operations at[] = { {AF_INET, KRB5_ADDRESS_INET, sizeof(struct sockaddr_in), ipv4_sockaddr2addr, @@ -351,8 +559,16 @@ 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 + {KRB5_ADDRESS_ADDRPORT, KRB5_ADDRESS_ADDRPORT, 0, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, addrport_print_addr, NULL, NULL, NULL, NULL }, + /* fake address type */ + {KRB5_ADDRESS_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]); @@ -386,33 +602,50 @@ find_atype(int atype) } krb5_error_code -krb5_sockaddr2address (const struct sockaddr *sa, krb5_address *addr) +krb5_sockaddr2address (krb5_context context, + const struct sockaddr *sa, krb5_address *addr) { struct addr_operations *a = find_af(sa->sa_family); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", + sa->sa_family); return KRB5_PROG_ATYPE_NOSUPP; + } return (*a->sockaddr2addr)(sa, addr); } krb5_error_code -krb5_sockaddr2port (const struct sockaddr *sa, int16_t *port) +krb5_sockaddr2port (krb5_context context, + const struct sockaddr *sa, int16_t *port) { struct addr_operations *a = find_af(sa->sa_family); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", + sa->sa_family); return KRB5_PROG_ATYPE_NOSUPP; + } return (*a->sockaddr2port)(sa, port); } krb5_error_code -krb5_addr2sockaddr (const krb5_address *addr, +krb5_addr2sockaddr (krb5_context context, + const krb5_address *addr, struct sockaddr *sa, - int *sa_size, + krb5_socklen_t *sa_size, int port) { struct addr_operations *a = find_atype(addr->addr_type); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address type %d not supported", + 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; } @@ -433,43 +666,53 @@ krb5_boolean krb5_sockaddr_uninteresting(const struct sockaddr *sa) { struct addr_operations *a = find_af(sa->sa_family); - if (a == NULL) + if (a == NULL || a->uninteresting == NULL) return TRUE; return (*a->uninteresting)(sa); } krb5_error_code -krb5_h_addr2sockaddr (int af, - const char *addr, struct sockaddr *sa, int *sa_size, +krb5_h_addr2sockaddr (krb5_context context, + int af, + const char *addr, struct sockaddr *sa, + krb5_socklen_t *sa_size, int port) { struct addr_operations *a = find_af(af); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", af); return KRB5_PROG_ATYPE_NOSUPP; + } (*a->h_addr2sockaddr)(addr, sa, sa_size, port); return 0; } krb5_error_code -krb5_h_addr2addr (int af, +krb5_h_addr2addr (krb5_context context, + int af, const char *haddr, krb5_address *addr) { struct addr_operations *a = find_af(af); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", af); return KRB5_PROG_ATYPE_NOSUPP; + } return (*a->h_addr2addr)(haddr, addr); } krb5_error_code -krb5_anyaddr (int af, +krb5_anyaddr (krb5_context context, + int af, struct sockaddr *sa, - int *sa_size, + krb5_socklen_t *sa_size, int port) { struct addr_operations *a = find_af (af); - if (a == NULL) + if (a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", af); return KRB5_PROG_ATYPE_NOSUPP; + } (*a->anyaddr)(sa, sa_size, port); return 0; @@ -479,26 +722,52 @@ krb5_error_code krb5_print_address (const krb5_address *addr, char *str, size_t len, size_t *ret_len) { + size_t ret; + int r = 0; struct addr_operations *a = find_atype(addr->addr_type); - if (a == NULL) { + if (len == 0) { + ret = 0; + r = EINVAL; + goto out; + } + + if (a == NULL || a->print_addr == NULL) { char *s; - size_t l; + int l; int i; + s = str; l = snprintf(s, len, "TYPE_%d:", addr->addr_type); + if (l < 0 || l > (len - 1)) { + ret = 0; + r = EINVAL; + goto out; + } s += l; - len -= len; + len -= l; for(i = 0; i < addr->address.length; i++) { l = snprintf(s, len, "%02x", ((char*)addr->address.data)[i]); + if (l < 0 || l > (len - 1)) { + ret = 0; + r = EINVAL; + goto out; + } len -= l; s += l; } - *ret_len = s - str; - return 0; + ret = s - str; + goto out; } - *ret_len = (*a->print_addr)(addr, str, len); - return 0; + ret = (*a->print_addr)(addr, str, len); + if (ret <= 0 || ret > (len - 1)) { + ret = 0; + r = EINVAL; + } +out: + if(ret_len != NULL) + *ret_len = ret; + return r; } krb5_error_code @@ -509,21 +778,25 @@ krb5_parse_address(krb5_context context, int i, n; struct addrinfo *ai, *a; int error; + int save_errno; for(i = 0; i < num_addrs; i++) { if(at[i].parse_addr) { - krb5_address a; - if((*at[i].parse_addr)(string, &a) == 0) { + krb5_address addr; + if((*at[i].parse_addr)(context, string, &addr) == 0) { ALLOC_SEQ(addresses, 1); - addresses->val[0] = a; + addresses->val[0] = addr; return 0; } } } error = getaddrinfo (string, NULL, NULL, &ai); - if (error) - return krb5_eai_to_heim_errno(error); + if (error) { + save_errno = errno; + krb5_set_error_string (context, "%s: %s", string, gai_strerror(error)); + return krb5_eai_to_heim_errno(error, save_errno); + } n = 0; for (a = ai; a != NULL; a = a->ai_next) @@ -531,9 +804,197 @@ krb5_parse_address(krb5_context context, ALLOC_SEQ(addresses, n); - for (a = ai, i = 0; a != NULL; a = a->ai_next, ++i) { - krb5_sockaddr2address (ai->ai_addr, &addresses->val[i]); + for (a = ai, i = 0; a != NULL; a = a->ai_next) { + if(krb5_sockaddr2address (context, ai->ai_addr, + &addresses->val[i]) == 0) + i++; } 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 == NULL) { + krb5_set_error_string (context, "Address family %d not supported", + addr1->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + if(a->order_addr != NULL) + return (*a->order_addr)(context, addr1, addr2); + a = find_atype(addr2->addr_type); + if(a == NULL) { + krb5_set_error_string (context, "Address family %d not supported", + addr2->addr_type); + return KRB5_PROG_ATYPE_NOSUPP; + } + 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; + if(addr1->address.length != addr2->address.length) + return addr1->address.length - addr2->address.length; + 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; +} diff --git a/kerberosV/src/lib/krb5/get_host_realm.c b/kerberosV/src/lib/krb5/get_host_realm.c index b1cc2a76db6..92e978cbb92 100644 --- a/kerberosV/src/lib/krb5/get_host_realm.c +++ b/kerberosV/src/lib/krb5/get_host_realm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan + * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,19 +34,19 @@ #include "krb5_locl.h" #include <resolve.h> -RCSID("$KTH: get_host_realm.c,v 1.25 1999/12/11 23:14:07 assar Exp $"); +RCSID("$KTH: get_host_realm.c,v 1.29 2002/08/28 13:36:57 nectar Exp $"); /* To automagically find the correct realm of a host (without * [domain_realm] in krb5.conf) add a text record for your domain with * the name of your realm, like this: * - * krb5-realm IN TXT FOO.SE + * _kerberos IN TXT "FOO.SE" * * The search is recursive, so you can add entries for specific * hosts. To find the realm of host a.b.c, it first tries - * krb5-realm.a.b.c, then krb5-realm.b.c and so on. + * _kerberos.a.b.c, then _kerberos.b.c and so on. * - * Also supported is _kerberos (following draft-ietf-cat-krb-dns-locate-01.txt) + * This method is described in draft-ietf-cat-krb-dns-locate-03.txt. * */ @@ -92,23 +92,33 @@ copy_txt_to_realms (struct resource_record *head, static int dns_find_realm(krb5_context context, const char *domain, - const char *dom_string, krb5_realm **realms) { + static char *default_labels[] = { "_kerberos", NULL }; char dom[MAXHOSTNAMELEN]; struct dns_reply *r; - int ret; + char **labels; + int i, j, ret; + labels = krb5_config_get_strings(context, NULL, "libdefaults", + "dns_lookup_realm_labels", NULL); + if(labels == NULL) + labels = default_labels; if(*domain == '.') domain++; - snprintf(dom, sizeof(dom), "%s.%s.", dom_string, domain); - r = dns_lookup(dom, "TXT"); - if(r == NULL) - return -1; - - ret = copy_txt_to_realms (r->head, realms); - dns_free_data(r); - return ret; + for (i = 0; labels[i] != NULL; i++) { + j = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); + if (j >= sizeof(dom) || j < 0) /* fucking solaris assholes */ + return -1; + r = dns_lookup(dom, "TXT"); + if(r != NULL) { + ret = copy_txt_to_realms (r->head, realms); + dns_free_data(r); + if(ret == 0) + return 0; + } + } + return -1; } /* @@ -142,34 +152,50 @@ config_find_realm(krb5_context context, krb5_error_code krb5_get_host_realm_int (krb5_context context, const char *host, + krb5_boolean use_dns, krb5_realm **realms) { - const char *p; + const char *p, *q; + krb5_boolean dns_locate_enable; + dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, + "libdefaults", "dns_lookup_realm", NULL); for (p = host; p != NULL; p = strchr (p + 1, '.')) { - if(config_find_realm(context, p, realms) == 0) - return 0; - else if(dns_find_realm(context, p, "krb5-realm", realms) == 0) - return 0; - else if(dns_find_realm(context, p, "_kerberos", realms) == 0) - return 0; + if(config_find_realm(context, p, realms) == 0) { + if(strcasecmp(*realms[0], "dns_locate") == 0) { + if(use_dns) + for (q = host; q != NULL; q = strchr(q + 1, '.')) + if(dns_find_realm(context, q, realms) == 0) + return 0; + continue; + } else + return 0; + } + else if(use_dns && dns_locate_enable) { + if(dns_find_realm(context, p, realms) == 0) + return 0; + } } p = strchr(host, '.'); if(p != NULL) { p++; *realms = malloc(2 * sizeof(krb5_realm)); - if (*realms == NULL) + if (*realms == NULL) { + krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; + } (*realms)[0] = strdup(p); if((*realms)[0] == NULL) { free(*realms); + krb5_set_error_string(context, "malloc: out of memory"); return ENOMEM; } strupr((*realms)[0]); (*realms)[1] = NULL; return 0; } + krb5_set_error_string(context, "unable to find realm of host %s", host); return KRB5_ERR_HOST_REALM_UNKNOWN; } @@ -190,5 +216,5 @@ krb5_get_host_realm(krb5_context context, host = hostname; } - return krb5_get_host_realm_int (context, host, realms); + return krb5_get_host_realm_int (context, host, 1, realms); } |