Fix IPv6 bug #5204, which caused krb5 DNS lookups
authorJeremy Allison <jra@samba.org>
Wed, 16 Jan 2008 21:21:46 +0000 (13:21 -0800)
committerJeremy Allison <jra@samba.org>
Wed, 16 Jan 2008 21:21:46 +0000 (13:21 -0800)
for a name '[<ipv6 addr>'.
Jeremy.

source/lib/util_sock.c
source/libads/kerberos.c

index 945506ea7776a0fe9e4d252d758e342db4e2d04f..10428113ae8b4b6d4ab13dcc7478b1f6775ae540 100644 (file)
@@ -475,6 +475,29 @@ bool is_address_any(const struct sockaddr_storage *psa)
        return false;
 }
 
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+       uint16_t port = 0;
+
+       if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+               /* IPv6 */
+               const struct sockaddr_in6 *sa6 =
+                       (const struct sockaddr_in6 *)pss;
+               port = ntohs(sa6->sin6_port);
+#endif
+       } else {
+               const struct sockaddr_in *sa =
+                       (const struct sockaddr_in *)pss;
+               port = ntohs(sa->sin_port);
+       }
+       return port;
+}
+
 /****************************************************************************
  Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
 ****************************************************************************/
@@ -518,7 +541,7 @@ char *print_canonical_sockaddr(TALLOC_CTX *ctx,
        char *dest = NULL;
        int ret;
 
-       ret = getnameinfo((const struct sockaddr *)pss,
+       ret = sys_getnameinfo((const struct sockaddr *)pss,
                        sizeof(struct sockaddr_storage),
                        addr, sizeof(addr),
                        NULL, 0,
@@ -1847,7 +1870,7 @@ const char *get_peer_name(int fd, bool force_lookup)
        }
 
        /* Look up the remote host name. */
-       ret = getnameinfo((struct sockaddr *)&ss,
+       ret = sys_getnameinfo((struct sockaddr *)&ss,
                        length,
                        name_buf,
                        sizeof(name_buf),
index e9222e840189b3715c6493451ab7794dd2ef9b77..f7e947b1e7fa977509ebcd56cff0c5c061669fc0 100644 (file)
@@ -25,6 +25,8 @@
 
 #ifdef HAVE_KRB5
 
+#define DEFAULT_KRB5_PORT 88
+
 #define LIBADS_CCACHE_NAME "MEMORY:libads"
 
 /*
@@ -665,6 +667,51 @@ int kerberos_kinit_password(const char *principal,
                                           NULL);
 }
 
+/************************************************************************
+************************************************************************/
+
+static char *print_kdc_line(char *mem_ctx,
+                       const char *prev_line,
+                       const struct sockaddr_storage *pss)
+{
+       char *kdc_str = NULL;
+
+       if (pss->ss_family == AF_INET) {
+               kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+                                       prev_line,
+                                        print_canonical_sockaddr(mem_ctx, pss));
+       } else {
+               char addr[INET6_ADDRSTRLEN];
+               uint16_t port = get_sockaddr_port(pss);
+
+               if (port != 0 && port != DEFAULT_KRB5_PORT) {
+                       /* Currently for IPv6 we can't specify a non-default
+                          krb5 port with an address, as this requires a ':'.
+                          Resolve to a name. */
+                       char hostname[MAX_DNS_NAME_LENGTH];
+                       if (sys_getnameinfo((const struct sockaddr *)pss,
+                                       sizeof(*pss),
+                                       hostname, sizeof(hostname),
+                                       NULL, 0,
+                                       NI_NAMEREQD) == 0) {
+                               /* Success, use host:port */
+                               kdc_str = talloc_asprintf(mem_ctx,
+                                       "%s\tkdc = %s:%u\n",
+                                        prev_line,
+                                       hostname,
+                                       (unsigned int)port);
+                               return kdc_str;
+                       }
+               }
+               kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+                                       prev_line,
+                                       print_sockaddr(addr,
+                                               sizeof(addr),
+                                               pss));
+       }
+       return kdc_str;
+}
+
 /************************************************************************
  Create a string list of available kdc's, possibly searching by sitename.
  Does DNS queries.
@@ -677,12 +724,10 @@ static char *get_kdc_ip_string(char *mem_ctx,
 {
        int i;
        struct ip_service *ip_srv_site = NULL;
-       struct ip_service *ip_srv_nonsite;
+       struct ip_service *ip_srv_nonsite = NULL;
        int count_site = 0;
        int count_nonsite;
-       char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
-                                       print_canonical_sockaddr(mem_ctx,
-                                                       pss));
+       char *kdc_str = print_kdc_line(mem_ctx, "", pss);
 
        if (kdc_str == NULL) {
                return NULL;
@@ -700,10 +745,9 @@ static char *get_kdc_ip_string(char *mem_ctx,
                        }
                        /* Append to the string - inefficient
                         * but not done often. */
-                       kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
-                               kdc_str,
-                               print_canonical_sockaddr(mem_ctx,
-                                                       &ip_srv_site[i].ss));
+                       kdc_str = print_kdc_line(mem_ctx,
+                                               kdc_str,
+                                               &ip_srv_site[i].ss);
                        if (!kdc_str) {
                                SAFE_FREE(ip_srv_site);
                                return NULL;
@@ -738,10 +782,9 @@ static char *get_kdc_ip_string(char *mem_ctx,
                }
 
                /* Append to the string - inefficient but not done often. */
-               kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+               kdc_str = print_kdc_line(mem_ctx,
                                kdc_str,
-                               print_canonical_sockaddr(mem_ctx,
-                                               &ip_srv_nonsite[i].ss));
+                               &ip_srv_nonsite[i].ss);
                if (!kdc_str) {
                        SAFE_FREE(ip_srv_site);
                        SAFE_FREE(ip_srv_nonsite);
@@ -873,8 +916,8 @@ bool create_local_private_krb5_conf_for_domain(const char *realm,
        }
 
        DEBUG(5,("create_local_private_krb5_conf_for_domain: wrote "
-               "file %s with realm %s KDC = %s\n",
-               fname, realm_upper, print_canonical_sockaddr(dname, pss) ));
+               "file %s with realm %s KDC list = %s\n",
+               fname, realm_upper, kdc_ip_string));
 
        /* Set the environment variable to this file. */
        setenv("KRB5_CONFIG", fname, 1);