diff --git a/lib/krb5/auth_context.c b/lib/krb5/auth_context.c index 17d55fda7..de600641a 100644 --- a/lib/krb5/auth_context.c +++ b/lib/krb5/auth_context.c @@ -132,6 +132,40 @@ krb5_auth_con_setaddrs(krb5_context context, return 0; } +static void +sockaddr2krb5_address (struct sockaddr *sa, + krb5_address *ka) +{ + switch (sa->sa_family) { + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + + ka->addr_type = AF_INET; + ka->address.length = sizeof(sin->sin_addr); + ka->address.data = &sin->sin_addr; + break; + } +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + case AF_INET6: { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + ka->addr_type = AF_INET; + ka->address.length = sizeof(struct in_addr); + ka->address.data = IN6_ADDR_V6_TO_V4(&sin6->sin6_addr); + } else { + ka->addr_type = AF_INET6; + ka->address.length = sizeof(sin6->sin6_addr); + ka->address.data = &sin6->sin6_addr; + } + break; + } +#endif + default: + break; + } +} + krb5_error_code krb5_auth_con_setaddrs_from_fd (krb5_context context, @@ -140,16 +174,19 @@ krb5_auth_con_setaddrs_from_fd (krb5_context context, { krb5_address *lptr = NULL, *rptr = NULL; krb5_address local_k_address, remote_k_address; +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + struct sockaddr_in6 local_addr, remote_addr; +#else struct sockaddr_in local_addr, remote_addr; +#endif int len; if (auth_context->local_address == NULL) { len = sizeof (local_addr); if (getsockname (fd, (struct sockaddr *)&local_addr, &len) < 0) return errno; - local_k_address.addr_type = AF_INET; - local_k_address.address.length = sizeof(local_addr.sin_addr); - local_k_address.address.data = &local_addr.sin_addr; + sockaddr2krb5_address((struct sockaddr *)&local_addr, + &local_k_address); lptr = &local_k_address; } @@ -157,9 +194,8 @@ krb5_auth_con_setaddrs_from_fd (krb5_context context, len = sizeof (remote_addr); if (getpeername (fd, (struct sockaddr *)&remote_addr, &len) < 0) return errno; - remote_k_address.addr_type = AF_INET; - remote_k_address.address.length = sizeof(remote_addr.sin_addr); - remote_k_address.address.data = &remote_addr.sin_addr; + sockaddr2krb5_address((struct sockaddr *)&remote_addr, + &remote_k_address); rptr = &remote_k_address; } diff --git a/lib/krb5/send_to_kdc.c b/lib/krb5/send_to_kdc.c index 92310f8e2..6f70de3bc 100644 --- a/lib/krb5/send_to_kdc.c +++ b/lib/krb5/send_to_kdc.c @@ -120,6 +120,18 @@ send_and_recv_http(int fd, return 0; } +static int +init_port(const char *s, int fallback) +{ + if (s) { + int tmp; + + sscanf (s, "%d", &tmp); + return htons(tmp); + } else + return fallback; +} + krb5_error_code krb5_sendto_kdc (krb5_context context, const krb5_data *send, @@ -141,61 +153,90 @@ krb5_sendto_kdc (krb5_context context, return err; } - for (i = 0; i < 3; ++i) + for (i = 0; i < context->max_retries; ++i) for (hp = hostlist; (p = *hp); ++hp) { - char *addr; - char *colon; - int http_flag = 0; + char *addr; + char *colon; + int http_flag = 0; - if(strncmp(p, "http://", 7) == 0){ - p += 7; - http_flag = 1; - } - colon = strchr (p, ':'); - if (colon) - *colon = '\0'; - hostent = gethostbyname (p); - if(hostent == NULL) - continue; - if (colon) - *colon++ = ':'; - while ((addr = *hostent->h_addr_list++)) { - struct sockaddr_in a; - int ret; - - if(http_flag) - fd = socket(AF_INET, SOCK_STREAM, 0); - else - fd = socket(AF_INET, SOCK_DGRAM, 0); - - if(fd < 0){ - return errno; - } - memset (&a, 0, sizeof(a)); - a.sin_family = AF_INET; - if (colon) { - int tmp; + if(strncmp(p, "http://", 7) == 0){ + p += 7; + http_flag = 1; + } + colon = strchr (p, ':'); + if (colon) + *colon = '\0'; +#ifdef HAVE_GETHOSTBYNAME2 + hostent = gethostbyname2 (p, AF_INET6); + if (hostent == NULL) + hostent = gethostbyname2 (p, AF_INET); +#else + hostent = gethostbyname (p); +#endif + if(hostent == NULL) + continue; + if (colon) + *colon++ = ':'; + while ((addr = *hostent->h_addr_list++)) { + int ret; + int family; + struct sockaddr *sa; + int sa_len; + struct sockaddr_in sin; +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + struct sockaddr_in6 sin6; +#endif - sscanf (colon, "%d", &tmp); - a.sin_port = htons(tmp); - } else - a.sin_port = port; - a.sin_addr = *((struct in_addr *)addr); - connect(fd, (struct sockaddr*)&a, sizeof(a)); + family = hostent->h_addrtype; - if(http_flag) - ret = send_and_recv_http(fd, context->kdc_timeout, - send, receive); - else + if(http_flag) + fd = socket(family, SOCK_STREAM, 0); + else + fd = socket(family, SOCK_DGRAM, 0); + + if(fd < 0) + return errno; + switch (family) { + case AF_INET : + memset(&sin, 0, sizeof(sin)); + sa_len = sizeof(sin); + sa = (struct sockaddr *)&sin; + sin.sin_family = family; + sin.sin_port = init_port(colon, port); + sin.sin_addr = *((struct in_addr *)addr); + break; +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + case AF_INET6: + memset(&sin6, 0, sizeof(sin6)); + sa_len = sizeof(sin6); + sa = (struct sockaddr *)&sin6; + sin6.sin6_family = family; + sin6.sin6_port = init_port(colon, port); + sin6.sin6_addr = *((struct in6_addr *)addr); + break; +#endif + default: + continue; + } + + if(connect(fd, sa, sa_len) < 0) { + close (fd); + continue; + } + + if(http_flag) + ret = send_and_recv_http(fd, context->kdc_timeout, + send, receive); + else - ret = send_and_recv (fd, context->kdc_timeout, 1, - send, receive); - close (fd); - if(ret == 0){ - krb5_free_krbhst (context, hostlist); - return 0; - } - } + ret = send_and_recv (fd, context->kdc_timeout, 1, + send, receive); + close (fd); + if(ret == 0){ + krb5_free_krbhst (context, hostlist); + return 0; + } + } } krb5_free_krbhst (context, hostlist); return KRB5_KDC_UNREACH; diff --git a/lib/krb5/sock_principal.c b/lib/krb5/sock_principal.c index 069e122f2..8ddec8674 100644 --- a/lib/krb5/sock_principal.c +++ b/lib/krb5/sock_principal.c @@ -48,16 +48,35 @@ krb5_sock_to_principal (krb5_context context, krb5_principal *ret_princ) { krb5_error_code ret; +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + struct sockaddr_in6 addr; +#else struct sockaddr_in addr; +#endif int len = sizeof(addr); struct hostent *hostent; if (getsockname (sock, (struct sockaddr *)&addr, &len) < 0) return errno; +#if defined(AF_INET6) && defined(HAVE_SOCKADDR_IN6) + if(len == sizeof(struct sockaddr_in6)) + hostent = gethostbyaddr ((const char *)&addr.sin6_addr, + sizeof(addr.sin6_addr), + addr.sin6_family); + else { + struct sockaddr_in *foo = (struct sockaddr_in *)&addr; + + hostent = gethostbyaddr ((const char *)&foo->sin_addr, + sizeof(foo->sin_addr), + foo->sin_family); + } +#else hostent = gethostbyaddr ((const char *)&addr.sin_addr, sizeof(addr.sin_addr), addr.sin_family); +#endif + if (hostent == NULL) return h_errno; return krb5_sname_to_principal (context,