localaddr.c (foreach_localaddr): support SIOCGIFNUM, for Solaris
authorKen Raeburn <raeburn@mit.edu>
Thu, 26 Apr 2001 03:54:43 +0000 (03:54 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 26 Apr 2001 03:54:43 +0000 (03:54 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13197 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/accessor.c
src/lib/krb5/os/changepw.c
src/lib/krb5/os/localaddr.c
src/lib/krb5/os/locate_kdc.c
src/lib/krb5/os/os-proto.h
src/lib/krb5/os/sendto_kdc.c

index 5ae26110fb156f7fb7a1629c6db43d163619b72c..c0dffe74925cfd22b9af9fc58a156feda0a155e0 100644 (file)
@@ -2,6 +2,10 @@
 
        * localaddr.c (socklen_t, socklen): Deleted; definitions now in
        k5-int.h instead.
+       (foreach_localaddr): Use SIOCGIFNUM if it's available and
+       SIOCGSIZIFCONF is not (e.g., Solaris 7 and 8).
+       (print_addr) [!HAVE_GETNAMEINFO]: Only declare variable buf if
+       AF_INET6 is defined.
 
 2001-03-31  Ken Raeburn  <raeburn@mit.edu>
 
index d0d0dc21dda9d144a029fb4fc8c3dd217ef2b764..d3c842a86ec155c4551ffcd55cb6fbf99edbd7a3 100644 (file)
@@ -37,6 +37,7 @@ krb5int_accessor(internals, version)
   if (version == KRB5INT_ACCESS_VERSION)
   {
     krb5int_access internals_temp;
+    internals_temp.krb5_locate_server = krb5int_locate_server;
     internals_temp.krb5_locate_kdc = krb5_locate_kdc;
     internals_temp.krb5_max_skdc_timeout = krb5_max_skdc_timeout;
     internals_temp.krb5_skdc_timeout_shift = krb5_skdc_timeout_shift;
index 61cfea01ff0976b05fd73f97b5762413fb3ee7e6..1eefe6d98658b7a5c1c19037b256bab3ae141e31 100644 (file)
@@ -8,7 +8,7 @@
  *   require a specific license from the United States Government.
  *   It is the responsibility of any person or organization contemplating
  *   export to obtain such a license before exporting.
- * 
+ *
  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  * distribute this software and its documentation for any purpose and
  * without fee is hereby granted, provided that the above copyright
@@ -22,7 +22,7 @@
  * M.I.T. makes no representations about the suitability of
  * this software for any purpose.  It is provided "as is" without express
  * or implied warranty.
- * 
+ *
  */
 
 #define NEED_SOCKETS
 #endif
 #endif /* _WIN32 && !__CYGWIN32__ */
 
+/* There's a lot of confusion between pointers to different sockaddr
+   types, and pointers with different degrees of indirection.  Use
+   this function in this file to ensure we don't do something silly
+   like cast a "sockaddr **" to a "sockaddr_in *".  */
+static struct sockaddr_in *sa2sin (struct sockaddr *sa)
+{
+    return (struct sockaddr_in *) sa;
+}
+#ifdef KRB5_USE_INET6xxNotUsed
+static struct sockaddr_in6 *sa2sin6 (struct sockaddr *sa)
+{
+    return (struct sockaddr_in6 *) sa;
+}
+#endif
+
 /*
  * Wrapper function for the two backends
  */
@@ -57,54 +72,30 @@ static krb5_error_code
 krb5_locate_kpasswd(context, realm, addr_pp, naddrs)
     krb5_context context;
     const krb5_data *realm;
-    struct sockaddr **addr_pp;
+    struct sockaddr ***addr_pp;
     int *naddrs;
 {
     krb5_error_code code;
-    int i;
 
-    /*
-     * We always try the local file first
-     */
-
-    code = krb5_locate_srv_conf(context, realm, "kpasswd_server",
-                                 addr_pp, naddrs, 0);
+    code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+                                 "kpasswd_server", "_kpasswd", 0,
+                                 DEFAULT_KPASSWD_PORT, 0);
     if (code) {
-        code = krb5_locate_srv_conf(context, realm, "admin_server", 
-                                     addr_pp, naddrs, 0);
-        if ( !code ) {
-            /* success with admin_server but now we need to change the port */
-            /* number to use DEFAULT_KPASSWD_PORT.                          */
-            for ( i=0;i<*naddrs;i++ ) {
-                struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
-                sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
-            }
-        }
+       code = krb5int_locate_server (context, realm, addr_pp, naddrs, 0,
+                                     "admin_server", "_kerberos-adm", 1,
+                                     DEFAULT_KPASSWD_PORT, 0);
+       if (!code) {
+           /* Success with admin_server but now we need to change the
+              port number to use DEFAULT_KPASSWD_PORT.  */
+           int i;
+           for ( i=0;i<*naddrs;i++ ) {
+               struct sockaddr *a = (*addr_pp)[i];
+               if (a->sa_family == AF_INET)
+                   sa2sin (a)->sin_port = htons(DEFAULT_KPASSWD_PORT);
+           }
+       }
     }
 
-#ifdef KRB5_DNS_LOOKUP
-    if (code) {
-        int use_dns = _krb5_use_dns_kdc(context);
-        if ( use_dns ) {
-            code = krb5_locate_srv_dns(realm, "_kpasswd", "_udp",
-                                        addr_pp, naddrs);
-            if ( code ) {
-                code = krb5_locate_srv_dns(realm, 
-                                            "_kerberos-adm", 
-                                            "_tcp",
-                                            addr_pp, naddrs);
-                if ( !code ) {
-                    /* success with admin_server but now we need to change the port */
-                    /* number to use DEFAULT_KPASSWD_PORT.                          */
-                    for ( i=0;i<*naddrs;i++ ) {
-                        struct sockaddr_in *sockin = (struct sockaddr_in *) addr_pp[i];
-                        sockin->sin_port = htons(DEFAULT_KPASSWD_PORT);
-                    }
-                }
-            }
-        }
-    }
-#endif /* KRB5_DNS_LOOKUP */
     return (code);
 }
 
@@ -125,7 +116,7 @@ krb5_change_password(context, creds, newpw, result_code,
     char *code_string;
     krb5_error_code code = 0;
     int i, addrlen;
-    struct sockaddr *addr_p, local_addr, remote_addr, tmp_addr;
+    struct sockaddr **addr_p, local_addr, remote_addr, tmp_addr;
     int naddr_p;
     int cc, local_result_code, tmp_len;
     SOCKET s1 = INVALID_SOCKET, s2 = INVALID_SOCKET;
@@ -137,18 +128,18 @@ krb5_change_password(context, creds, newpw, result_code,
     memset(&chpw_req, 0, sizeof(krb5_data));
     memset(&chpw_rep, 0, sizeof(krb5_data));
     memset(&ap_req, 0, sizeof(krb5_data));
-    
+
     /* initialize auth_context so that we know we have to free it */
     if ((code = krb5_auth_con_init(context, &auth_context)))
          goto cleanup;
-    
-    if ((code = krb5_mk_req_extended(context, &auth_context, 
+
+    if ((code = krb5_mk_req_extended(context, &auth_context,
                                     AP_OPTS_USE_SUBKEY,
                                     NULL, creds, &ap_req)))
          goto cleanup;
 
-    if ((code = krb5_locate_kpasswd(context, 
-                                    krb5_princ_realm(context, creds->client), 
+    if ((code = krb5_locate_kpasswd(context,
+                                    krb5_princ_realm(context, creds->client),
                                     &addr_p, &naddr_p)))
         goto cleanup;
 
@@ -156,7 +147,7 @@ krb5_change_password(context, creds, newpw, result_code,
        is left unconnected in case the server is multihomed and routes
        are asymmetric.  s2 is connected to resolve routes and get
        addresses.  this is the *only* way to get proper addresses for
-       multihomed hosts if routing is asymmetric.  
+       multihomed hosts if routing is asymmetric.
 
        A related problem in the server, but not the client, is that
        many os's have no way to disconnect a connected udp socket, so
@@ -168,212 +159,207 @@ krb5_change_password(context, creds, newpw, result_code,
        hostname resolution to get the local ip addr) will work and
        interoperate if the client is single-homed. */
 
-    if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) 
-      {
+    if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+       code = SOCKET_ERRNO;
+       goto cleanup;
+    }
+
+    if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET) {
+       code = SOCKET_ERRNO;
+       goto cleanup;
+    }
+
+    for (i=0; i<naddr_p; i++) {
+       fd_set fdset;
+       struct timeval timeout;
+
+       /* XXX Now the locate_ functions can return IPv6 addresses.  */
+       if (addr_p[i]->sa_family != AF_INET)
+           continue;
+
+       if (connect(s2, addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR) {
+           if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+               continue; /* try the next addr */
+
            code = SOCKET_ERRNO;
            goto cleanup;
-      }
+       }
+
+        addrlen = sizeof(local_addr);
+
+       if (getsockname(s2, &local_addr, &addrlen) < 0) {
+           if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+               continue; /* try the next addr */
 
-    if ((s2 = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
-      {
            code = SOCKET_ERRNO;
            goto cleanup;
-      }
-
-    for (i=0; i<naddr_p; i++) 
-      {
-               fd_set fdset;
-               struct timeval timeout;
-
-               if (connect(s2, &addr_p[i], sizeof(addr_p[i])) == SOCKET_ERROR) 
-                 {
-                   if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
-                         continue; /* try the next addr */
-                   
-                   code = SOCKET_ERRNO;
-                   goto cleanup;
-                 }
-      
-        addrlen = sizeof(local_addr);
+       }
 
-               if (getsockname(s2, &local_addr, &addrlen) < 0) 
-                 {
-                   if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
-                         continue; /* try the next addr */
-                   
-                   code = SOCKET_ERRNO;
-                       goto cleanup;
-                 }
-
-               /* some brain-dead OS's don't return useful information from
-                * the getsockname call.  Namely, windows and solaris.  */
-
-               if (((struct sockaddr_in *)&local_addr)->sin_addr.s_addr != 0) 
-                 {
-                   local_kaddr.addrtype = ADDRTYPE_INET;
-                   local_kaddr.length = sizeof(((struct sockaddr_in *) &local_addr)->sin_addr);
-                   local_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &local_addr)->sin_addr);
-                 } 
-               else 
-                 {
-                   krb5_address **addrs;
-
-                   krb5_os_localaddr(context, &addrs);
-                   
-                   local_kaddr.magic = addrs[0]->magic;
-                   local_kaddr.addrtype = addrs[0]->addrtype;
-                   local_kaddr.length = addrs[0]->length;
-                   local_kaddr.contents = malloc(addrs[0]->length);
-                   memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
-
-                   krb5_free_addresses(context, addrs);
-                 }
-
-               addrlen = sizeof(remote_addr);
-               if (getpeername(s2, &remote_addr, &addrlen) < 0) 
-                 {
-                   if ((SOCKET_ERRNO == ECONNREFUSED) || (SOCKET_ERRNO == EHOSTUNREACH))
-                         continue; /* try the next addr */
-                   
-                   code = SOCKET_ERRNO;
-                       goto cleanup;
-                 }
-
-               remote_kaddr.addrtype = ADDRTYPE_INET;
-               remote_kaddr.length = sizeof(((struct sockaddr_in *) &remote_addr)->sin_addr);
-               remote_kaddr.contents = (krb5_octet *) &(((struct sockaddr_in *) &remote_addr)->sin_addr);
-
-               /* mk_priv requires that the local address be set.
-                 getsockname is used for this.  rd_priv requires that the
-                 remote address be set.  recvfrom is used for this.  If
-                 rd_priv is given a local address, and the message has the
-                 recipient addr in it, this will be checked.  However, there
-                 is simply no way to know ahead of time what address the
-                 message will be delivered *to*.  Therefore, it is important
-                 that either no recipient address is in the messages when
-                 mk_priv is called, or that no local address is passed to
-                 rd_priv.  Both is a better idea, and I have done that.  In
-                 summary, when mk_priv is called, *only* a local address is
-                 specified.  when rd_priv is called, *only* a remote address
-                 is specified.  Are we having fun yet?  */
-
-               if ((code = krb5_auth_con_setaddrs(context, auth_context, 
-                                                  &local_kaddr, NULL)))
-                 {
-                   code = SOCKET_ERRNO;
-                       goto cleanup;
-                 }
-
-               if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req, 
-                                            newpw, &chpw_req)))
-                 {
-                   code = SOCKET_ERRNO;
-                       goto cleanup;
-                 }
-
-               if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0, 
-                                (struct sockaddr *) &addr_p[i], 
-                                sizeof(addr_p[i]))) != chpw_req.length) 
-                 {
-                   if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
-                                    (SOCKET_ERRNO == EHOSTUNREACH)))
-                         continue; /* try the next addr */
-                   
-                   code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
-                       goto cleanup;
-                 }
-
-               chpw_rep.length = 1500;
-               chpw_rep.data = (char *) malloc(chpw_rep.length);
-
-               /* XXX need a timeout/retry loop here */
-               FD_ZERO (&fdset);
-               FD_SET (s1, &fdset);
-               timeout.tv_sec = 120;
-               timeout.tv_usec = 0;
-               switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
-               case -1:
-                   code = SOCKET_ERRNO;
-                   goto cleanup;
-               case 0:
-                   code = ETIMEDOUT;
-                   goto cleanup;
-               default:
-                   /* fall through */
-                   ;
-               }
-
-               /* "recv" would be good enough here... except that Windows/NT
-                  commits the atrocity of returning -1 to indicate failure,
-                  but leaving errno set to 0.
-                  
-                  "recvfrom(...,NULL,NULL)" would seem to be a good enough
-                  alternative, and it works on NT, but it doesn't work on
-                  SunOS 4.1.4 or Irix 5.3.  Thus we must actually accept the
-                  value and discard it. */
-               tmp_len = sizeof(tmp_addr);
-               if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length, 
-                                  0, &tmp_addr, &tmp_len)) < 0) 
-                 {
-                   code = SOCKET_ERRNO;
-                   goto cleanup;
-                 }
-
-               closesocket(s1);
-               s1 = INVALID_SOCKET;
-               closesocket(s2);
-               s2 = INVALID_SOCKET;
-
-               chpw_rep.length = cc;
-
-               if ((code = krb5_auth_con_setaddrs(context, auth_context,
-                                                  NULL, &remote_kaddr)))
-                 goto cleanup;
-
-               if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
-                                            &local_result_code, 
-                                            result_string)))
-                 goto cleanup;
-
-               if (result_code)
-                 *result_code = local_result_code;
-
-               if (result_code_string) 
-                 {
-                   if ((code = krb5_chpw_result_code_string(context, 
-                                                            local_result_code,
-                                                            &code_string)))
-                         goto cleanup;
-
-                   result_code_string->length = strlen(code_string);
-                   if ((result_code_string->data =
-                           (char *) malloc(result_code_string->length)) == NULL)
-                         return(ENOMEM);
-                   strncpy(result_code_string->data, code_string, result_code_string->length);
-                 }
-
-               code = 0;
+       /* some brain-dead OS's don't return useful information from
+        * the getsockname call.  Namely, windows and solaris.  */
+
+       if (sa2sin(&local_addr)->sin_addr.s_addr != 0) {
+           local_kaddr.addrtype = ADDRTYPE_INET;
+           local_kaddr.length = sizeof(sa2sin(&local_addr)->sin_addr);
+           local_kaddr.contents = (krb5_octet *) &sa2sin(&local_addr)->sin_addr;
+       } else {
+           krb5_address **addrs;
+
+           krb5_os_localaddr(context, &addrs);
+
+           local_kaddr.magic = addrs[0]->magic;
+           local_kaddr.addrtype = addrs[0]->addrtype;
+           local_kaddr.length = addrs[0]->length;
+           local_kaddr.contents = malloc(addrs[0]->length);
+           memcpy(local_kaddr.contents, addrs[0]->contents, addrs[0]->length);
+
+           krb5_free_addresses(context, addrs);
+       }
+
+       addrlen = sizeof(remote_addr);
+       if (getpeername(s2, &remote_addr, &addrlen) < 0) {
+           if (SOCKET_ERRNO == ECONNREFUSED || SOCKET_ERRNO == EHOSTUNREACH)
+               continue; /* try the next addr */
+
+           code = SOCKET_ERRNO;
+           goto cleanup;
+       }
+
+       remote_kaddr.addrtype = ADDRTYPE_INET;
+       remote_kaddr.length = sizeof(sa2sin(&remote_addr)->sin_addr);
+       remote_kaddr.contents = (krb5_octet *) &sa2sin(&remote_addr)->sin_addr;
+
+       /* mk_priv requires that the local address be set.
+          getsockname is used for this.  rd_priv requires that the
+          remote address be set.  recvfrom is used for this.  If
+          rd_priv is given a local address, and the message has the
+          recipient addr in it, this will be checked.  However, there
+          is simply no way to know ahead of time what address the
+          message will be delivered *to*.  Therefore, it is important
+          that either no recipient address is in the messages when
+          mk_priv is called, or that no local address is passed to
+          rd_priv.  Both is a better idea, and I have done that.  In
+          summary, when mk_priv is called, *only* a local address is
+          specified.  when rd_priv is called, *only* a remote address
+          is specified.  Are we having fun yet?  */
+
+       if ((code = krb5_auth_con_setaddrs(context, auth_context,
+                                          &local_kaddr, NULL))) {
+           code = SOCKET_ERRNO;
+           goto cleanup;
+       }
+
+       if ((code = krb5_mk_chpw_req(context, auth_context, &ap_req,
+                                    newpw, &chpw_req)))
+       {
+           code = SOCKET_ERRNO;
+           goto cleanup;
+       }
+
+       if ((cc = sendto(s1, chpw_req.data, (int) chpw_req.length, 0,
+                        addr_p[i], sizeof(addr_p[i]))) != chpw_req.length)
+       {
+           if ((cc < 0) && ((SOCKET_ERRNO == ECONNREFUSED) ||
+                            (SOCKET_ERRNO == EHOSTUNREACH)))
+               continue; /* try the next addr */
+
+           code = (cc < 0) ? SOCKET_ERRNO : ECONNABORTED;
+           goto cleanup;
+       }
+
+       chpw_rep.length = 1500;
+       chpw_rep.data = (char *) malloc(chpw_rep.length);
+
+       /* XXX need a timeout/retry loop here */
+       FD_ZERO (&fdset);
+       FD_SET (s1, &fdset);
+       timeout.tv_sec = 120;
+       timeout.tv_usec = 0;
+       switch (select (s1 + 1, &fdset, 0, 0, &timeout)) {
+       case -1:
+           code = SOCKET_ERRNO;
+           goto cleanup;
+       case 0:
+           code = ETIMEDOUT;
+           goto cleanup;
+       default:
+           /* fall through */
+           ;
+       }
+
+       /* "recv" would be good enough here... except that Windows/NT
+          commits the atrocity of returning -1 to indicate failure,
+          but leaving errno set to 0.
+
+          "recvfrom(...,NULL,NULL)" would seem to be a good enough
+          alternative, and it works on NT, but it doesn't work on
+          SunOS 4.1.4 or Irix 5.3.  Thus we must actually accept the
+          value and discard it. */
+       tmp_len = sizeof(tmp_addr);
+       if ((cc = recvfrom(s1, chpw_rep.data, (int) chpw_rep.length,
+                          0, &tmp_addr, &tmp_len)) < 0)
+       {
+           code = SOCKET_ERRNO;
+           goto cleanup;
+       }
+
+       closesocket(s1);
+       s1 = INVALID_SOCKET;
+       closesocket(s2);
+       s2 = INVALID_SOCKET;
+
+       chpw_rep.length = cc;
+
+       if ((code = krb5_auth_con_setaddrs(context, auth_context,
+                                          NULL, &remote_kaddr)))
+           goto cleanup;
+
+       if ((code = krb5_rd_chpw_rep(context, auth_context, &chpw_rep,
+                                    &local_result_code,
+                                    result_string)))
+           goto cleanup;
+
+       if (result_code)
+           *result_code = local_result_code;
+
+       if (result_code_string) {
+           if ((code = krb5_chpw_result_code_string(context,
+                                                    local_result_code,
+                                                    &code_string)))
                goto cleanup;
-      }
+
+           result_code_string->length = strlen(code_string);
+           if ((result_code_string->data =
+                (char *) malloc(result_code_string->length)) == NULL)
+               return(ENOMEM);
+           strncpy(result_code_string->data, code_string, result_code_string->length);
+       }
+
+       code = 0;
+       goto cleanup;
+    }
 
     code = SOCKET_ERRNO;
-    
+
 cleanup:
-    if(auth_context != NULL)
-      krb5_auth_con_free(context, auth_context);
-    
-    if(addr_p != NULL)
-      krb5_xfree(addr_p);
-    
-    if(s1 != INVALID_SOCKET)
-      closesocket(s1);
-    
-    if(s2 != INVALID_SOCKET)
-      closesocket(s2);
-      
+    if (auth_context != NULL)
+       krb5_auth_con_free(context, auth_context);
+
+    if (addr_p != NULL) {
+       for (i = 0; i < naddr_p; i++)
+           krb5_xfree (addr_p[i]);
+       krb5_xfree(addr_p);
+    }
+
+    if (s1 != INVALID_SOCKET)
+       closesocket(s1);
+
+    if (s2 != INVALID_SOCKET)
+       closesocket(s2);
+
     krb5_free_data_contents(context, &chpw_req);
     krb5_free_data_contents(context, &chpw_rep);
-       krb5_free_data_contents(context, &ap_req);
-    
+    krb5_free_data_contents(context, &ap_req);
+
     return(code);
 }
index 1fc558d581de542b331f384be7519d094fe74f04..3eeb52e30b276287a14b31e5f6d14265fa1172ea 100644 (file)
@@ -300,6 +300,9 @@ foreach_localaddr (/*@null@*/ void *data,
     int ifconfsize = -1;
 #endif
     int retval = 0;
+#ifdef SIOCGIFNUM
+    int numifs = -1;
+#endif
 
     s = socket (USE_AF, USE_TYPE, USE_PROTO);
     if (s < 0)
@@ -315,6 +318,10 @@ foreach_localaddr (/*@null@*/ void *data,
        current_buf_size = ifconfsize;
        est_if_count = ifconfsize / est_ifreq_size;
     }
+#elif defined (SIOCGIFNUM)
+    code = ioctl (s, SIOCGIFNUM, &numifs);
+    if (!code && numifs > 0)
+       est_if_count = numifs;
 #endif
     if (current_buf_size == 0)
        current_buf_size = est_ifreq_size * est_if_count;
@@ -341,6 +348,8 @@ foreach_localaddr (/*@null@*/ void *data,
     if (current_buf_size - size < sizeof (struct ifreq) + 40
 #ifdef SIOCGSIZIFCONF
        && ifconfsize <= 0
+#elif defined (SIOCGIFNUM)
+       && numifs <= 0
 #endif
        ) {
        size_t new_size;
@@ -468,7 +477,9 @@ static int print_addr (/*@unused@*/ void *dataptr, struct sockaddr *sa)
        printf ("addr %s\n", hostbuf);
     return 0;
 #else
+#ifdef AF_INET6
     char buf[50];
+#endif
     printf ("family %2d ", sa->sa_family);
     switch (sa->sa_family) {
     case AF_INET:
index 48a0147700d363d094285c5434f2d999e712a045..808f868fc16bfb367da88728123fc005688d8efd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lib/krb5/os/locate_kdc.c
  *
- * Copyright 1990 by the Massachusetts Institute of Technology.
+ * Copyright 1990,2000,2001 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
  *
  * Export of this software from the United States of America may
@@ -50,9 +50,6 @@
 #endif
 
 #define MAX_DNS_NAMELEN (15*(MAXHOSTNAMELEN + 1)+1)
-#ifndef KPASSWD_PORTNAME
-#define KPASSWD_PORTNAME "kpasswd"
-#endif
 
 #if KRB5_DNS_LOOKUP_KDC
 #define DEFAULT_LOOKUP_KDC 1
@@ -107,32 +104,286 @@ _krb5_use_dns_realm(context)
 
 #endif /* KRB5_DNS_LOOKUP */
 
+static int get_port (const char *service, int stream, int defalt)
+{
+#ifdef HAVE_GETADDRINFO
+    struct addrinfo hints = { 0 };
+    struct addrinfo *ai;
+    int err;
+
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = stream ? SOCK_STREAM : SOCK_DGRAM;
+    err = getaddrinfo (NULL, service, &hints, &ai);
+    if (err == 0 && ai != 0) {
+       if (ai->ai_addr->sa_family == AF_INET) {
+           int port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+           freeaddrinfo (ai);
+           return port;
+       }
+       freeaddrinfo (ai);
+    }
+    /* Any error - don't complain, just use default.  */
+    return htons (defalt);
+#else
+    struct servent *sp;
+    sp = getservbyname (service, stream ? "tcp" : "udp"); /* NOT THREAD SAFE */
+    if (sp)
+       return sp->s_port;
+    return htons (defalt);
+#endif
+}
+
+struct addrlist {
+    struct sockaddr **addrs;
+    int naddrs;
+    int space;
+};
+#define ADDRLIST_INIT { 0, 0, 0 }
+
+static int
+grow_list (struct addrlist *lp, int nmore)
+{
+    int i;
+    int newspace = lp->space + nmore;
+    size_t newsize = newspace * sizeof (struct addrlist);
+    struct sockaddr **newaddrs;
+
+    newaddrs = realloc (lp->addrs, newsize);
+
+    if (newaddrs == NULL)
+       return errno;
+    for (i = lp->space; i < newspace; i++)
+       newaddrs[i] = NULL;
+    lp->addrs = newaddrs;
+    lp->space = newspace;
+    return 0;
+}
+
+static void
+free_list (struct addrlist *lp)
+{
+    int i;
+    for (i = 0; i < lp->naddrs; i++)
+       free (lp->addrs[i]);
+    free (lp->addrs);
+    lp->addrs = NULL;
+    lp->naddrs = lp->space = 0;
+}
+
+static int
+add_sockaddr_to_list (struct addrlist *lp, const struct sockaddr *addr,
+                     size_t len)
+{
+    struct sockaddr *copy;
+
+#ifdef TEST
+    fprintf (stderr, "\tadding sockaddr family %2d", addr->sa_family);
+    if (addr->sa_family == AF_INET)
+       fprintf (stderr, "\t%s",
+                inet_ntoa (((const struct sockaddr_in *)addr)->sin_addr));
+    fprintf (stderr, "\n");
+#endif
+
+    if (lp->naddrs == lp->space) {
+       int err = grow_list (lp, 1);
+       if (err)
+           return err;
+    }
+    copy = malloc (len);
+    if (copy == NULL)
+       return errno;
+    memcpy (copy, addr, len);
+    lp->addrs[lp->naddrs++] = copy;
+    return 0;
+}
+
+#ifdef HAVE_GETADDRINFO
+static int translate_ai_error (int err)
+{
+    switch (err) {
+    case 0:
+       return 0;
+    case EAI_ADDRFAMILY:
+    case EAI_BADFLAGS:
+    case EAI_FAMILY:
+    case EAI_SOCKTYPE:
+    case EAI_SERVICE:
+       /* All of these indicate bad inputs to getaddrinfo.  */
+       return EINVAL;
+    case EAI_AGAIN:
+       /* Translate to standard errno code.  */
+       return EAGAIN;
+    case EAI_MEMORY:
+       /* Translate to standard errno code.  */
+       return ENOMEM;
+    case EAI_NODATA:
+    case EAI_NONAME:
+       /* Name not known or no address data, but no error.  Do
+          nothing more.  */
+       return 0;
+    case EAI_SYSTEM:
+       /* System error, duh.  */
+       return errno;
+    default:
+       /* An error code we haven't handled?  */
+       return EINVAL;
+    }
+}
+
+static int add_addrinfo_to_list (struct addrlist *lp, struct addrinfo *a)
+{
+    return add_sockaddr_to_list (lp, a->ai_addr, a->ai_addrlen);
+}
+
+static void set_port_num (struct sockaddr *addr, int num)
+{
+    switch (addr->sa_family) {
+    case AF_INET:
+       ((struct sockaddr_in *)addr)->sin_port = num;
+       break;
+    case AF_INET6:
+       ((struct sockaddr_in6 *)addr)->sin6_port = num;
+       break;
+    }
+}
+#endif
+
+/* There's also gethostbyname_r, which is IPv4-only but thread-safe;
+   it wants the caller to supply scratch space and a hostent
+   structure.  Let's go for IPv6 support before thread safety, though;
+   it's easier to accomplish, and will probably be finished first
+   anyways.  */
+#if !defined (HAVE_GETADDRINFO) && !defined (HAVE_GETIPNODEBYNAME)
+#undef getipnodebyname
+#define freehostent(X) ((void)(X))
+#ifdef HAVE_GETHOSTBYNAME2
+#define getipnodebyname(NAME,AF,FLAGS,ERRP) (gethostbyname2(NAME,AF))
+#else
+#define getipnodebyname(NAME,AF,FLAGS,ERRP) ((AF)==AF_INET?gethostbyname(NAME):(struct hostent *)0)
+#endif
+#endif
+
+static int
+add_host_to_list (struct addrlist *lp, const char *hostname,
+                 int port, int secport)
+{
+#ifdef HAVE_GETADDRINFO
+    int err;
+    struct addrinfo *addrs, *a;
+
+#ifdef TEST
+    fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname,
+            ntohs (port), ntohs (secport));
+#endif
+
+    err = getaddrinfo (hostname, NULL, NULL, &addrs);
+    if (err)
+       return translate_ai_error (err);
+    for (a = addrs; a; a = a->ai_next) {
+       set_port_num (a->ai_addr, port);
+       err = add_addrinfo_to_list (lp, a);
+       if (err)
+           break;
+
+       if (secport == 0)
+           continue;
+
+       set_port_num (a->ai_addr, secport);
+       err = add_addrinfo_to_list (lp, a);
+       if (err)
+           break;
+    }
+    freeaddrinfo (addrs);
+    return err;
+#else
+    int err;
+    struct hostent *hp;
+    int i;
+
+#ifdef TEST
+    fprintf (stderr, "adding hostname %s, ports %d,%d\n", hostname, port, secport);
+#endif
+
+    hp = getipnodebyname (hostname, AF_INET, 0, &err);
+    if (hp != NULL) {
+       for (i = 0; hp->h_addr_list[i] != 0; i++) {
+           struct sockaddr_in sin4;
+
+           memset (&sin4, 0, sizeof (sin4));
+           memcpy (&sin4.sin_addr, hp->h_addr_list[i],
+                   sizeof (sin4.sin_addr));
+           sin4.sin_family = AF_INET;
+           sin4.sin_port = port;
+           err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4,
+                                       sizeof (sin4));
+           if (err)
+               break;
+           if (secport != 0) {
+               sin4.sin_port = secport;
+               err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin4,
+                                           sizeof (sin4));
+           }
+
+           if (err)
+               break;
+       }
+       freehostent (hp);
+    }
+#if defined (KRB5_USE_INET6)
+    hp = getipnodebyname (hostname, AF_INET6, 0, &err); /* NOT THREAD SAFE */
+    if (hp != NULL) {
+       for (i = 0; hp->h_addr_list[i] != 0; i++) {
+           struct sockaddr_in6 sin6;
+
+           memset (&sin6, 0, sizeof (sin6));
+           memcpy (&sin6.sin6_addr, hp->h_addr_list[i],
+                   sizeof (sin6.sin6_addr));
+           sin6.sin6_family = AF_INET6;
+           sin6.sin6_port = port;
+           err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6,
+                                       sizeof (sin6));
+           if (err)
+               break;
+           if (secport != 0) {
+               sin6.sin6_port = secport;
+               err = add_sockaddr_to_list (lp, (struct sockaddr *) &sin6,
+                                           sizeof (sin6));
+               if (err)
+                   break;
+           }
+       }
+       freehostent (hp);
+    }
+#endif
+    return 0;
+#endif
+}
+
 /*
  * returns count of number of addresses found
  * if master is non-NULL, it is filled in with the index of
  * the master kdc
  */
 
-krb5_error_code
-krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
+static krb5_error_code
+krb5_locate_srv_conf_1(context, realm, name, addrlist, get_masters,
+                      udpport, sec_udpport)
     krb5_context context;
     const krb5_data *realm;
     const char * name;
-    struct sockaddr **addr_pp;
-    int *naddrs;
+    struct addrlist *addrlist;
     int get_masters;
+    int udpport, sec_udpport;
 {
     const char *realm_srv_names[4];
     char **masterlist, **hostlist, *host, *port, *cp;
     krb5_error_code code;
-    int i, j, out, count, ismaster;
-    struct sockaddr *addr_p;
-    struct sockaddr_in *sin_p;
-    struct hostent *hp;
-    struct servent *sp;
-#ifdef HAVE_NETINET_IN_H
-    u_short udpport;
-    u_short sec_udpport;
+    int i, j, count, ismaster;
+
+#ifdef TEST
+    fprintf (stderr,
+            "looking in krb5.conf for realm %s entry %s; ports %d,%d\n",
+            realm->data, name, ntohs (udpport), ntohs (sec_udpport));
 #endif
 
     if ((host = malloc(realm->length + 1)) == NULL) 
@@ -158,27 +409,6 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
        return code;
      }
 
-#ifdef HAVE_NETINET_IN_H
-    if ( !strcmp(name,"kpasswd_server") ) {
-        if ((sp = getservbyname(KPASSWD_PORTNAME, "udp")))
-            udpport = sp->s_port;
-        else
-            udpport = htons(DEFAULT_KPASSWD_PORT);
-        sec_udpport = 0;
-    } else {
-    if ((sp = getservbyname(KDC_PORTNAME, "udp")))
-       udpport = sp->s_port;
-        else 
-            udpport = htons(KRB5_DEFAULT_PORT);
-    if ((sp = getservbyname(KDC_SECONDARY_PORTNAME, "udp")))
-       sec_udpport = sp->s_port;
-        else
-            sec_udpport = htons(KRB5_DEFAULT_SEC_PORT);
-    }
-#endif
-    if (sec_udpport == udpport)
-       sec_udpport = 0;
-
     count = 0;
     while (hostlist && hostlist[count])
            count++;
@@ -186,7 +416,7 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
     if (count == 0) {
         profile_free_list(hostlist);
        krb5_xfree(host);
-       *naddrs = 0;
+       addrlist->naddrs = 0;
        return 0;
     }
     
@@ -232,16 +462,9 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
            count = count * 2;
 #endif
 
-    addr_p = (struct sockaddr *)malloc (sizeof (struct sockaddr) * count);
-    if (addr_p == NULL) {
-        if (hostlist)
-            profile_free_list(hostlist);
-        if (masterlist)
-            profile_free_list(masterlist);
-       return ENOMEM;
-    }
+    for (i=0; hostlist[i]; i++) {
+       int p1, p2;
 
-    for (i=0, out=0; hostlist[i]; i++) {
        host = hostlist[i];
        /*
         * Strip off excess whitespace
@@ -258,10 +481,6 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
            port++;
        }
 
-       if ((hp = gethostbyname(hostlist[i])) == 0) {
-           continue;
-       }
-
        ismaster = 0;
        if (masterlist) {
            for (j=0; masterlist[j]; j++) {
@@ -271,44 +490,37 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
            }
        }
 
-        if ( !get_masters || ismaster ) {
-            switch (hp->h_addrtype) {
+       if (get_masters && !ismaster)
+           continue;
 
-#ifdef HAVE_NETINET_IN_H
-            case AF_INET:
-                for (j=0; hp->h_addr_list[j]; j++) {
-                    sin_p = (struct sockaddr_in *) &addr_p[out++];
-                    memset ((char *)sin_p, 0, sizeof(struct sockaddr));
-                    sin_p->sin_family = hp->h_addrtype;
-                    sin_p->sin_port = port ? htons(atoi(port)) : udpport;
-                    memcpy((char *)&sin_p->sin_addr,
-                            (char *)hp->h_addr_list[j],
-                            sizeof(struct in_addr));
-                    if (out+1 >= count) {
-                        count += 5;
-                        addr_p = (struct sockaddr *)
-                            realloc ((char *)addr_p,
-                                      sizeof(struct sockaddr) * count);
-                        if (addr_p == NULL) {
-                            if ( hostlist )
-                                profile_free_list(hostlist);
-                            if ( masterlist )
-                                profile_free_list(masterlist);
-                            return ENOMEM;
-                        }
-                    }
-                    if (sec_udpport && !port) {
-                        addr_p[out] = addr_p[out-1];
-                        sin_p = (struct sockaddr_in *) &addr_p[out++];
-                        sin_p->sin_port = sec_udpport;
-                    }
-                }
-                break;
+       if (port) {
+           unsigned long l;
+#ifdef HAVE_STROUL
+           char *endptr;
+           l = strtoul (port, &endptr, 10);
+           if (endptr == NULL || *endptr != 0)
+               return EINVAL;
+#else
+           l = atoi (port);
 #endif
-            default:
-                break;
-            }
-        }
+           /* L is unsigned, don't need to check <0.  */
+           if (l > 65535)
+               return EINVAL;
+           p1 = htons (l);
+           p2 = 0;
+       } else {
+           p1 = udpport;
+           p2 = sec_udpport;
+       }
+
+       code = add_host_to_list (addrlist, hostlist[i], p1, p2);
+       if (code) {
+           if (hostlist)
+               profile_free_list (hostlist);
+           if (masterlist)
+               profile_free_list (masterlist);
+           return code;
+       }
     }
 
     if (hostlist)
@@ -316,40 +528,56 @@ krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters)
     if (masterlist)
         profile_free_list(masterlist);
 
-    if (out == 0) {     /* Couldn't resolve any KDC names */
-        free (addr_p);
-        return KRB5_REALM_CANT_RESOLVE;
-    }
+    return 0;
+}
 
-    *addr_pp = addr_p;
-    *naddrs = out;
+static krb5_error_code
+krb5_locate_srv_conf(context, realm, name, addr_pp, naddrs, get_masters,
+                    udpport, sec_udpport)
+    krb5_context context;
+    const krb5_data *realm;
+    const char * name;
+    struct sockaddr ***addr_pp;
+    int *naddrs;
+    int get_masters;
+    int udpport, sec_udpport;
+{
+    krb5_error_code ret;
+    struct addrlist al = ADDRLIST_INIT;
+
+    ret = krb5_locate_srv_conf_1 (context, realm, name, &al,
+                                 get_masters, udpport, sec_udpport);
+    if (ret) {
+       free_list (&al);
+       return ret;
+    }
+    if (al.naddrs == 0)                /* Couldn't resolve any KDC names */
+       return KRB5_REALM_CANT_RESOLVE;
+    *addr_pp = al.addrs;
+    *naddrs = al.naddrs;
     return 0;
 }
 
+
 #ifdef KRB5_DNS_LOOKUP
 
 /*
  * Lookup a KDC via DNS SRV records
  */
 
-krb5_error_code
-krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
+static krb5_error_code
+krb5_locate_srv_dns_1 (realm, service, protocol, addrlist)
     const krb5_data *realm;
     const char *service;
     const char *protocol;
-    struct sockaddr **addr_pp;
-    int *naddrs;
+    struct addrlist *addrlist;
 {
-    int out, j, count;
     union {
         unsigned char bytes[2048];
         HEADER hdr;
     } answer;
     unsigned char *p=NULL;
     char host[MAX_DNS_NAMELEN], *h;
-    struct sockaddr *addr = NULL;
-    struct sockaddr_in *sin_p = NULL;
-    struct hostent *hp = NULL;
     int type, class;
     int priority, weight, size, len, numanswers, numqueries, rdlen;
     unsigned short port;
@@ -364,13 +592,7 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
 
     struct srv_dns_entry *head = NULL;
     struct srv_dns_entry *srv = NULL, *entry = NULL;
-
-    out = 0;
-    addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
-    if (addr == NULL)
-       return ENOMEM;
-
-    count = 1;
+    krb5_error_code code = 0;
 
     /*
      * First off, build a query of the form:
@@ -390,19 +612,22 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
            realm->data);
 
     /* Realm names don't (normally) end with ".", but if the query
-    doesn't end with "." and doesn't get an answer as is, the
-    resolv code will try appending the local domain.  Since the
-    realm names are absolutes, let's stop that.  
+       doesn't end with "." and doesn't get an answer as is, the
+       resolv code will try appending the local domain.  Since the
+       realm names are absolutes, let's stop that.  
 
-    But only if a name has been specified.  If we are performing
-    a search on the prefix alone then the intention is to allow
-    the local domain or domain search lists to be expanded.
-    */
+       But only if a name has been specified.  If we are performing
+       a search on the prefix alone then the intention is to allow
+       the local domain or domain search lists to be expanded.  */
 
     h = host + strlen (host);
     if ((h > host) && (h[-1] != '.') && ((h - host + 1) < sizeof(host)))
         strcpy (h, ".");
 
+#ifdef TEST
+    fprintf (stderr, "sending DNS SRV query for %s\n", host);
+#endif
+
     size = res_search(host, C_IN, T_SRV, answer.bytes, sizeof(answer.bytes));
 
     if (size < hdrsize)
@@ -546,36 +771,20 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
     if (head == NULL)
        goto out;
 
+#ifdef TEST
+    fprintf (stderr, "walking answer list:\n");
+#endif
     for (entry = head; entry != NULL; entry = entry->next) {
-       hp = gethostbyname(entry->host);
-       if (hp != 0) {
-           switch (hp->h_addrtype) {
-#ifdef HAVE_NETINET_IN_H
-            case AF_INET:
-               for (j=0; hp->h_addr_list[j]; j++) {
-                   sin_p = (struct sockaddr_in *) &addr[out++];
-                   memset ((char *) sin_p, 0, sizeof (struct sockaddr));
-                   sin_p->sin_family = hp->h_addrtype;
-                   sin_p->sin_port = htons(entry->port);
-                   memcpy((char *) &sin_p->sin_addr,
-                          (char *) hp->h_addr_list[j],
-                          sizeof(struct in_addr));
-                   if (out + 1 >= count) {
-                       count += 5;
-                       addr = (struct sockaddr *)
-                               realloc((char *) addr,
-                                       sizeof(struct sockaddr) * count);
-                       if (!addr)
-                           goto out;
-                   }
-               }
-               break;
-#endif /* HAVE_NETINET_IN_H */
-           default:
-               break;
-           }
-       }
+#ifdef TEST
+       fprintf (stderr, "\tport=%d host=%s\n", entry->port, entry->host);
+#endif
+       code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0);
+       if (code)
+           break;
     }
+#ifdef TEST
+    fprintf (stderr, "[end]\n");
+#endif
 
     for (entry = head; entry != NULL; ) {
        free(entry->host);
@@ -590,15 +799,22 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
     if (srv)
         free(srv);
 
-    if (out == 0) {    /* No good servers */
-        if (addr)
-            free(addr);
-       return KRB5_REALM_CANT_RESOLVE;
-    }
+    return code;
+}
 
-    *addr_pp = addr;
-    *naddrs = out;
-    return 0;
+static krb5_error_code
+krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
+    const krb5_data *realm;
+    const char *service;
+    const char *protocol;
+    struct sockaddr ***addr_pp;
+    int *naddrs;
+{
+    struct addrlist al = ADDRLIST_INIT;
+    krb5_error_code code;
+
+    code = krb5_locate_srv_dns_1 (realm, service, protocol, &al);
+    return code;
 }
 #endif /* KRB5_DNS_LOOKUP */
 
@@ -607,56 +823,63 @@ krb5_locate_srv_dns(realm, service, protocol, addr_pp, naddrs)
  */
 
 krb5_error_code
-krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters)
-    krb5_context context;
-    const krb5_data *realm;
-    struct sockaddr **addr_pp;
-    int *naddrs;
-    int get_masters;
+krb5int_locate_server (krb5_context context, const krb5_data *realm,
+                      struct sockaddr ***addr_pp, int *naddrs,
+                      int get_masters,
+                      const char *profname, const char *dnsname,
+                      int is_stream,
+                      /* network order port numbers! */
+                      int dflport1, int dflport2)
 {
     krb5_error_code code;
+    struct addrlist al = ADDRLIST_INIT;
 
     /*
      * We always try the local file first
      */
 
-    code = krb5_locate_srv_conf(context, realm, "kdc", addr_pp, naddrs,
-                                 get_masters);
+    code = krb5_locate_srv_conf(context, realm, profname, &al, get_masters);
 
 #ifdef KRB5_DNS_LOOKUP
     if (code) {
-        int use_dns = _krb5_use_dns_kdc(context);
-        if ( use_dns ) {
-            code = krb5_locate_srv_dns(realm, 
-                                        get_masters ? "_kerberos-master" : "_kerberos",
-                                        "_udp", addr_pp, naddrs);
-        }
+       int use_dns = _krb5_use_dns_kdc(context);
+       if (use_dns)
+           code = krb5_locate_srv_dns(realm, dnsname,
+                                      is_stream ? "_tcp" : "_udp", &al);
     }
 #endif /* KRB5_DNS_LOOKUP */
-    return (code);
+    if (al.naddrs == 0) {      /* No good servers */
+       return KRB5_REALM_CANT_RESOLVE;
+    }
+    if (code == 0) {
+       *addr_pp = al.addrs;
+       *naddrs = al.naddrs;
+    }
+    return code;
 }
 
-#if 0 /* Why is this useful?  It's not used now, and it's certainly
-        not useful if you don't have the DNS code enabled.  -KR  */
-
-/*
- * It turns out that it is really useful to be able to use these functions
- * for other things (like admin servers), so create an abstract function
- * for this
- */
-
 krb5_error_code
-krb5_locate_server(realm, name, proto, addr_pp, naddrs)
+krb5_locate_kdc(context, realm, addr_pp, naddrs, get_masters)
+    krb5_context context;
     const krb5_data *realm;
-    const char *name, *proto;
-    struct sockaddr **addr_pp;
+    struct sockaddr ***addr_pp;
     int *naddrs;
+    int get_masters;
 {
-    krb5_error_code code = KRB5_REALM_UNKNOWN;
-#ifdef KRB5_DNS_LOOKUP
-    code = krb5_locate_srv_dns(realm, name, proto,
-                                (struct sockaddr **) addr_pp, naddrs);
-#endif /* KRB5_DNS_LOOKUP */
-    return (code);
+    int udpport, sec_udpport;
+
+    udpport = get_port (KDC_PORTNAME, 0, KRB5_DEFAULT_PORT);
+    sec_udpport = get_port (KDC_SECONDARY_PORTNAME, 0,
+                           (udpport == htons (KRB5_DEFAULT_PORT)
+                            ? KRB5_DEFAULT_SEC_PORT
+                            : KRB5_DEFAULT_PORT));
+    if (sec_udpport == udpport)
+       sec_udpport = 0;
+
+    return krb5int_locate_server (context, realm, addr_pp, naddrs, get_masters,
+                                 "kdc",
+                                 (get_masters
+                                  ? "_kerberos-master"
+                                  : "_kerberos"),
+                                 0, udpport, sec_udpport);
 }
-#endif
index 12e2afb4813adf7cf3de176f6c4e62d103ab5adc..ceba9b477f1258936fc4193fc39f493079b12d23 100644 (file)
@@ -34,7 +34,7 @@
 krb5_error_code krb5_locate_kdc
     PROTOTYPE((krb5_context,
               const krb5_data *,
-              struct sockaddr **,
+              struct sockaddr ***,
               int *,
               int));
 #endif
index 58c97f837cc3fc4aba0ed23a3e439d6e95b8c9ac..86665b412bde540d8287565d1e0febf9961a7b82 100644 (file)
@@ -63,7 +63,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
     int use_master;
 {
     register int timeout, host, i;
-    struct sockaddr *addr;
+    struct sockaddr **addr;
     int naddr;
     int sent, nready;
     krb5_error_code retval;
@@ -90,6 +90,8 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
        socklist[i] = INVALID_SOCKET;
 
     if (!(reply->data = malloc(krb5_max_dgram_size))) {
+       for (i = 0; i < naddr; i++)
+           krb5_xfree (addr[i]);
        krb5_xfree(addr);
        krb5_xfree(socklist);
        return ENOMEM;
@@ -133,7 +135,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
                 * protocol exists to support a particular socket type
                 * within a given protocol family.
                 */
-               socklist[host] = socket(addr[host].sa_family, SOCK_DGRAM, 0);
+               socklist[host] = socket(addr[host]->sa_family, SOCK_DGRAM, 0);
                if (socklist[host] == INVALID_SOCKET)
                    continue;           /* try other hosts */
                /* have a socket to send/recv from */
@@ -143,7 +145,7 @@ krb5_sendto_kdc (context, message, realm, reply, use_master)
                   sendto, recvfrom.  The connect here may return an error if
                   the destination host is known to be unreachable. */
                if (connect(socklist[host],
-                           &addr[host], sizeof(addr[host])) == SOCKET_ERROR)
+                           addr[host], sizeof(addr[host])) == SOCKET_ERROR)
                  continue;
            }
            if (send(socklist[host],