Separate interface address processing from Kerberos-related functions.
authorKen Raeburn <raeburn@mit.edu>
Fri, 25 Feb 2000 20:27:43 +0000 (20:27 +0000)
committerKen Raeburn <raeburn@mit.edu>
Fri, 25 Feb 2000 20:27:43 +0000 (20:27 +0000)
* localaddr.c (foreach_localaddr): Broken out from old krb5_os_localaddr.
Iterates over all active interface addresses, invoking callback functions;
knows nothing about Kerberos.
(count_addrs, allocate, add_addr): New callback functions.
(krb5_os_localaddr): Use the above.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12069 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/localaddr.c

index 598d169f6f49a364a6d0c56e3e1b5878b4eec3d9..4db3cc384c8c0cedb9e69464593c6794e392c8c1 100644 (file)
@@ -1,3 +1,11 @@
+2000-02-25  Ken Raeburn  <raeburn@raeburn.org>
+
+       * localaddr.c (foreach_localaddr): Broken out from old
+       krb5_os_localaddr.  Iterates over all active interface addresses,
+       invoking callback functions; knows nothing about Kerberos.
+       (count_addrs, allocate, add_addr): New callback functions.
+       (krb5_os_localaddr): Use the above.
+
 2000-02-16  Ken Raeburn  <raeburn@mit.edu>
 
        * localaddr.c (krb5_os_localaddr): Dynamically grow buffer used
index e59bd38b5a5052ab14c403eb90becdadeeda1c82..30ebecb9d0230b5d7b73d6b90232d115f6bcd857 100644 (file)
  * Add more address families here.
  */
 
+extern int errno;
+
+/*
+ * Return all the protocol addresses of this host.
+ *
+ * We could kludge up something to return all addresses, assuming that
+ * they're valid kerberos protocol addresses, but we wouldn't know the
+ * real size of the sockaddr or know which part of it was actually the
+ * host part.
+ *
+ * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
+ */
+
+struct localaddr_data {
+    int count, mem_err, cur_idx;
+    krb5_address **addr_temp;
+};
+
+static int
+count_addrs (void *P_data, struct sockaddr *a)
+{
+    struct localaddr_data *data = P_data;
+    switch (a->sa_family) {
+    case AF_INET:
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+#endif
+#ifdef KRB5_USE_NS
+    case AF_XNS:
+#endif
+       data->count++;
+       break;
+    default:
+       break;
+    }
+    return 0;
+}
+
+static int
+allocate (void *P_data)
+{
+    struct localaddr_data *data = P_data;
+    int i;
+
+    data->addr_temp = (krb5_address **) malloc (data->count * sizeof (krb5_address *));
+    if (data->addr_temp == 0)
+       return 1;
+    for (i = 0; i < data->count; i++)
+       data->addr_temp[i] = 0;
+    return 0;
+}
+
+static int
+add_addr (void *P_data, struct sockaddr *a)
+{
+    struct localaddr_data *data = P_data;
+    krb5_address *address = 0;
+
+    switch (a->sa_family) {
+#ifdef HAVE_NETINET_IN_H
+    case AF_INET:
+    {
+       struct sockaddr_in *in = (struct sockaddr_in *) a;
+
+       address = (krb5_address *) malloc (sizeof(krb5_address));
+       if (address) {
+           address->magic = KV5M_ADDRESS;
+           address->addrtype = ADDRTYPE_INET;
+           address->length = sizeof(struct in_addr);
+           address->contents = (unsigned char *)malloc(address->length);
+           if (!address->contents) {
+               krb5_xfree(address);
+               address = 0;
+               data->mem_err++;
+           } else {
+               memcpy ((char *)address->contents, (char *)&in->sin_addr, 
+                       address->length);
+               break;
+           }
+       } else
+           data->mem_err++;
+    }
+
+#ifdef KRB5_USE_INET6
+    case AF_INET6:
+    {
+       struct sockaddr_in6 *in = (struct sockaddr_in6 *) a;
+       
+       if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr))
+           return 0;
+       
+       address = (krb5_address *) malloc (sizeof(krb5_address));
+       if (address) {
+           address->magic = KV5M_ADDRESS;
+           address->addrtype = ADDRTYPE_INET6;
+           address->length = sizeof(struct in6_addr);
+           address->contents = (unsigned char *)malloc(address->length);
+           if (!address->contents) {
+               krb5_xfree(address);
+               address = 0;
+               data->mem_err++;
+           } else {
+               memcpy ((char *)address->contents, (char *)&in->sin6_addr,
+                       address->length);
+               break;
+           }
+       } else
+           data->mem_err++;
+    }
+#endif /* KRB5_USE_INET6 */
+#endif /* netinet/in.h */
+
+#ifdef KRB5_USE_NS
+    case AF_XNS:
+    {  
+       struct sockaddr_ns *ns = (struct sockaddr_ns *) a;
+       address = (krb5_address *)
+           malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
+       if (address) {
+           address->magic = KV5M_ADDRESS;
+           address->addrtype = ADDRTYPE_XNS; 
+
+           /* XXX should we perhaps use ns_host instead? */
+
+           address->length = sizeof(struct ns_addr);
+           address->contents = (unsigned char *)malloc(address->length);
+           if (!address->contents) {
+               krb5_xfree(address);
+               address = 0;
+               data->mem_err++;
+           } else {
+               memcpy ((char *)address->contents,
+                       (char *)&ns->sns_addr,
+                       address->length);
+               break;
+           }
+       } else
+           data->mem_err++;
+       break;
+    }
+#endif
+    /*
+     * Add more address families here..
+     */
+    default:
+       break;
+    }
+    if (address) {
+       data->addr_temp[data->cur_idx++] = address;
+    }
+
+    return data->mem_err;
+}
+
+/* Keep this in sync with kdc/network.c version.  */
+
 /*
  * BSD 4.4 defines the size of an ifreq to be
  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
 #define ifreq_size(i) sizeof(struct ifreq)
 #endif /* HAVE_SA_LEN*/
 
-
-
-extern int errno;
-
-/*
- * Return all the protocol addresses of this host.
- *
- * We could kludge up something to return all addresses, assuming that
- * they're valid kerberos protocol addresses, but we wouldn't know the
- * real size of the sockaddr or know which part of it was actually the
- * host part.
- *
- * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
- */
-
-KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
-krb5_os_localaddr(context, addr)
-    krb5_context context;
-    krb5_address FAR * FAR * FAR *addr;
+static int
+foreach_localaddr (data, pass1fn, betweenfn, pass2fn)
+    void *data;
+    int (*pass1fn) (void *, struct sockaddr *);
+    int (*betweenfn) (void *);
+    int (*pass2fn) (void *, struct sockaddr *);
 {
     struct ifreq *ifr, ifreq;
     struct ifconf ifc;
     int s, code, n, i;
-    int est_if_count = 8, est_addr_count, est_ifreq_size;
+    int est_if_count = 8, est_ifreq_size;
     char *buf = 0;
     size_t current_buf_size = 0;
-    krb5_address **addr_temp = 0;
-    int n_found;
-    int mem_err = 0;
     
     s = socket (USE_AF, USE_TYPE, USE_PROTO);
     if (s < 0)
@@ -167,161 +307,92 @@ krb5_os_localaddr(context, addr)
     }
 
     n = ifc.ifc_len;
-    est_addr_count = (n + sizeof (struct ifreq) - 1) / sizeof (struct ifreq);
-    addr_temp = malloc (sizeof (krb5_address *) * est_addr_count);
-    n_found = 0;
 
     for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
-       krb5_address *address;
        ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
 
        strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
-       if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0)
-           continue;
-
+       if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0
 #ifdef IFF_LOOPBACK
-       if (ifreq.ifr_flags & IFF_LOOPBACK) 
-           continue;
+           /* None of the current callers want loopback addresses.  */
+           || (ifreq.ifr_flags & IFF_LOOPBACK)
 #endif
+           /* Ignore interfaces that are down.  */
+           || !(ifreq.ifr_flags & IFF_UP)) {
+           /* mark for next pass */
+           ifr->ifr_name[0] = 0;
 
-       if (!(ifreq.ifr_flags & IFF_UP)) 
-           /* interface is down; skip */
            continue;
+       }
 
-       /* ifr->ifr_addr has what we want! */
-       switch (ifr->ifr_addr.sa_family) {
-#ifdef HAVE_NETINET_IN_H
-       case AF_INET:
-           {
-               struct sockaddr_in *in =
-                   (struct sockaddr_in *)&ifr->ifr_addr;
-
-               address = (krb5_address *)
-                   malloc (sizeof(krb5_address));
-               if (address) {
-                   address->magic = KV5M_ADDRESS;
-                   address->addrtype = ADDRTYPE_INET;
-                   address->length = sizeof(struct in_addr);
-                   address->contents = (unsigned char *)malloc(address->length);
-                   if (!address->contents) {
-                       krb5_xfree(address);
-                       address = 0;
-                       mem_err++;
-                   } else {
-                       memcpy ((char *)address->contents,
-                               (char *)&in->sin_addr, 
-                               address->length);
-                       break;
-                   }
-               } else mem_err++;
-           }
-#ifdef KRB5_USE_INET6
-       case AF_INET6:
-           {
-               struct sockaddr_in6 *in =
-                   (struct sockaddr_in6 *)&ifr->ifr_addr;
-
-               if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr))
-                   continue;
-
-               address = (krb5_address *)
-                   malloc (sizeof(krb5_address));
-               if (address) {
-                   address->magic = KV5M_ADDRESS;
-                   address->addrtype = ADDRTYPE_INET6;
-                   address->length = sizeof(struct in6_addr);
-                   address->contents = (unsigned char *)malloc(address->length);
-                   if (!address->contents) {
-                       krb5_xfree(address);
-                       address = 0;
-                       mem_err++;
-                   } else {
-                       memcpy ((char *)address->contents,
-                               (char *)&in->sin6_addr,
-                               address->length);
-                       break;
-                   }
-               } else mem_err++;
-           }
-#endif /* KRB5_USE_INET6 */
-#endif /* netinet/in.h */
-
-#ifdef KRB5_USE_NS
-       case AF_XNS:
-           {  
-               struct sockaddr_ns *ns =
-                   (struct sockaddr_ns *)&ifr->ifr_addr;
-               address = (krb5_address *)
-                   malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
-               if (address) {
-                   address->magic = KV5M_ADDRESS;
-                   address->addrtype = ADDRTYPE_XNS; 
-
-                   /* XXX should we perhaps use ns_host instead? */
-
-                   address->length = sizeof(struct ns_addr);
-                   address->contents = (unsigned char *)malloc(address->length);
-                   if (!address->contents) {
-                       krb5_xfree(address);
-                       address = 0;
-                       mem_err++;
-                   } else {
-                       memcpy ((char *)address->contents,
-                               (char *)&ns->sns_addr,
-                               address->length);
-                       break;
-                   }
-               } else mem_err++;
-               break;
-           }
-#endif
-       /*
-        * Add more address families here..
-        */
-       default:
-           continue;
+       if ((*pass1fn) (data, &ifr->ifr_addr)) {
+           abort ();
        }
-       if (address) {
-           /* I doubt this will ever happen, since we were
-              conservative in figuring est_addr_count in the first
-              place...  */
-           if (n_found == est_addr_count - 1) {
-               krb5_address **nw;
-               est_addr_count *= 2;
-               nw = realloc (addr_temp,
-                             sizeof (krb5_address *) * est_addr_count);
-               if (nw == 0) {
-                   mem_err++;
-                   free (address);
-                   break;
-               }
-               addr_temp = nw;
+    }
+
+    if (betweenfn && (*betweenfn)(data)) {
+       abort ();
+    }
+
+    if (pass2fn)
+       for (i = 0; i < n; i+= ifreq_size(*ifr) ) {
+           ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
+
+           if (ifr->ifr_name[0] == 0)
+               /* Marked in first pass to be ignored.  */
+               continue;
+
+           if ((*pass2fn) (data, &ifr->ifr_addr)) {
+               abort ();
            }
-           addr_temp[n_found++] = address;
        }
-       address = 0;
-    }
     closesocket(s);
     free (buf);
 
-    *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
-    if (*addr == 0)
-       mem_err++;
-    
-    if (mem_err) {
-       for (i=0; i<n_found; i++) {
-           krb5_xfree(addr_temp[i]);
-           addr_temp[i] = 0;
+    return 0;
+}
+
+
+
+KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
+krb5_os_localaddr(context, addr)
+    krb5_context context;
+    krb5_address FAR * FAR * FAR *addr;
+{
+    struct localaddr_data data = { 0 };
+    int r;
+
+    r = foreach_localaddr (&data, count_addrs, allocate, add_addr);
+    if (r != 0) {
+       int i;
+       if (data.addr_temp) {
+           for (i = 0; i < data.count; i++)
+               krb5_xfree (data.addr_temp[i]);
+           free (data.addr_temp);
        }
-       free (addr_temp);
-       return ENOMEM;
+       if (r == -1 && data.mem_err)
+           return ENOMEM;
+       else
+           return r;
     }
-    
-    for (i=0; i<n_found; i++) {
-       (*addr)[i] = addr_temp[i];
+
+    if (data.mem_err)
+       return ENOMEM;
+    else if (data.cur_idx == 0)
+       abort ();
+    else if (data.cur_idx == data.count)
+       *addr = data.addr_temp;
+    else {
+       /* This can easily happen if we have IPv6 link-local
+          addresses.  Just shorten the array.  */
+       *addr = (krb5_address **) realloc (data.addr_temp,
+                                          (sizeof (krb5_address *)
+                                           * data.cur_idx));
+       if (*addr == 0)
+           /* Okay, shortening failed, but the original should still
+              be intact.  */
+           *addr = data.addr_temp;
     }
-    (*addr)[n_found] = 0;
-    free (addr_temp);
     return 0;
 }