Use standard heimdal function for finding interfaces - libreplace provides support...
authorJelmer Vernooij <jelmer@samba.org>
Sun, 2 Nov 2008 17:14:53 +0000 (18:14 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Sun, 2 Nov 2008 17:14:53 +0000 (18:14 +0100)
source4/heimdal/lib/krb5/get_addrs.c [new file with mode: 0644]
source4/heimdal_build/internal.mk
source4/heimdal_build/krb5-glue.c

diff --git a/source4/heimdal/lib/krb5/get_addrs.c b/source4/heimdal/lib/krb5/get_addrs.c
new file mode 100644 (file)
index 0000000..fb45d08
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "krb5_locl.h"
+
+RCSID("$Id: get_addrs.c 23815 2008-09-13 09:21:03Z lha $");
+
+#ifdef __osf__
+/* hate */
+struct rtentry;
+struct mbuf;
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <ifaddrs.h>
+
+static krb5_error_code
+gethostname_fallback (krb5_context context, krb5_addresses *res)
+{
+    krb5_error_code ret;
+    char hostname[MAXHOSTNAMELEN];
+    struct hostent *hostent;
+
+    if (gethostname (hostname, sizeof(hostname))) {
+       ret = errno;
+       krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret));
+       return ret;
+    }
+    hostent = roken_gethostbyname (hostname);
+    if (hostent == NULL) {
+       ret = errno;
+       krb5_set_error_message (context, ret, "gethostbyname %s: %s",
+                               hostname, strerror(ret));
+       return ret;
+    }
+    res->len = 1;
+    res->val = malloc (sizeof(*res->val));
+    if (res->val == NULL) {
+       krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+       return ENOMEM;
+    }
+    res->val[0].addr_type = hostent->h_addrtype;
+    res->val[0].address.data = NULL;
+    res->val[0].address.length = 0;
+    ret = krb5_data_copy (&res->val[0].address,
+                         hostent->h_addr,
+                         hostent->h_length);
+    if (ret) {
+       free (res->val);
+       return ret;
+    }
+    return 0;
+}
+
+enum {
+    LOOP            = 1,       /* do include loopback interfaces */
+    LOOP_IF_NONE    = 2,       /* include loopback if no other if's */
+    EXTRA_ADDRESSES = 4,       /* include extra addresses */
+    SCAN_INTERFACES = 8                /* scan interfaces for addresses */
+};
+
+/*
+ * Try to figure out the addresses of all configured interfaces with a
+ * lot of magic ioctls.
+ */
+
+static krb5_error_code
+find_all_addresses (krb5_context context, krb5_addresses *res, int flags)
+{
+    struct sockaddr sa_zero;
+    struct ifaddrs *ifa0, *ifa;
+    krb5_error_code ret = ENXIO;
+    unsigned int num, idx;
+    krb5_addresses ignore_addresses;
+
+    res->val = NULL;
+
+    if (getifaddrs(&ifa0) == -1) {
+       ret = errno;
+       krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret));
+       return (ret);
+    }
+
+    memset(&sa_zero, 0, sizeof(sa_zero));
+
+    /* First, count all the ifaddrs. */
+    for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++)
+       /* nothing */;
+
+    if (num == 0) {
+       freeifaddrs(ifa0);
+       krb5_set_error_message(context, ENXIO, N_("no addresses found", ""));
+       return (ENXIO);
+    }
+
+    if (flags & EXTRA_ADDRESSES) {
+       /* we'll remove the addresses we don't care about */
+       ret = krb5_get_ignore_addresses(context, &ignore_addresses);
+       if(ret)
+           return ret;
+    }
+
+    /* Allocate storage for them. */
+    res->val = calloc(num, sizeof(*res->val));
+    if (res->val == NULL) {
+       krb5_free_addresses(context, &ignore_addresses);
+       freeifaddrs(ifa0);
+       krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
+       return ENOMEM;
+    }
+
+    /* Now traverse the list. */
+    for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) {
+       if ((ifa->ifa_flags & IFF_UP) == 0)
+           continue;
+       if (ifa->ifa_addr == NULL)
+           continue;
+       if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
+           continue;
+       if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
+           continue;
+       if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+           /* We'll deal with the LOOP_IF_NONE case later. */
+           if ((flags & LOOP) == 0)
+               continue;
+       }
+
+       ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]);
+       if (ret) {
+           /*
+            * The most likely error here is going to be "Program
+            * lacks support for address type".  This is no big
+            * deal -- just continue, and we'll listen on the
+            * addresses who's type we *do* support.
+            */
+           continue;
+       }
+       /* possibly skip this address? */
+       if((flags & EXTRA_ADDRESSES) &&
+          krb5_address_search(context, &res->val[idx], &ignore_addresses)) {
+           krb5_free_address(context, &res->val[idx]);
+           flags &= ~LOOP_IF_NONE; /* we actually found an address,
+                                       so don't add any loop-back
+                                       addresses */
+           continue;
+       }
+
+       idx++;
+    }
+
+    /*
+     * If no addresses were found, and LOOP_IF_NONE is set, then find
+     * the loopback addresses and add them to our list.
+     */
+    if ((flags & LOOP_IF_NONE) != 0 && idx == 0) {
+       for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) {
+           if ((ifa->ifa_flags & IFF_UP) == 0)
+               continue;
+           if (ifa->ifa_addr == NULL)
+               continue;
+           if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
+               continue;
+           if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
+               continue;
+
+           if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
+               ret = krb5_sockaddr2address(context,
+                                           ifa->ifa_addr, &res->val[idx]);
+               if (ret) {
+                   /*
+                    * See comment above.
+                    */
+                   continue;
+               }
+               if((flags & EXTRA_ADDRESSES) &&
+                  krb5_address_search(context, &res->val[idx],
+                                      &ignore_addresses)) {
+                   krb5_free_address(context, &res->val[idx]);
+                   continue;
+               }
+               idx++;
+           }
+       }
+    }
+
+    if (flags & EXTRA_ADDRESSES)
+       krb5_free_addresses(context, &ignore_addresses);
+    freeifaddrs(ifa0);
+    if (ret) {
+       free(res->val);
+       res->val = NULL;
+    } else
+       res->len = idx;        /* Now a count. */
+    return (ret);
+}
+
+static krb5_error_code
+get_addrs_int (krb5_context context, krb5_addresses *res, int flags)
+{
+    krb5_error_code ret = -1;
+
+    if (flags & SCAN_INTERFACES) {
+       ret = find_all_addresses (context, res, flags);
+       if(ret || res->len == 0)
+           ret = gethostname_fallback (context, res);
+    } else {
+       res->len = 0;
+       res->val = NULL;
+       ret = 0;
+    }
+
+    if(ret == 0 && (flags & EXTRA_ADDRESSES)) {
+       krb5_addresses a;
+       /* append user specified addresses */
+       ret = krb5_get_extra_addresses(context, &a);
+       if(ret) {
+           krb5_free_addresses(context, res);
+           return ret;
+       }
+       ret = krb5_append_addresses(context, res, &a);
+       if(ret) {
+           krb5_free_addresses(context, res);
+           return ret;
+       }
+       krb5_free_addresses(context, &a);
+    }
+    if(res->len == 0) {
+       free(res->val);
+       res->val = NULL;
+    }
+    return ret;
+}
+
+/*
+ * Try to get all addresses, but return the one corresponding to
+ * `hostname' if we fail.
+ *
+ * Only include loopback address if there are no other.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res)
+{
+    int flags = LOOP_IF_NONE | EXTRA_ADDRESSES;
+
+    if (context->scan_interfaces)
+       flags |= SCAN_INTERFACES;
+
+    return get_addrs_int (context, res, flags);
+}
+
+/*
+ * Try to get all local addresses that a server should listen to.
+ * If that fails, we return the address corresponding to `hostname'.
+ */
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res)
+{
+    return get_addrs_int (context, res, LOOP | SCAN_INTERFACES);
+}
index 85ce6d3ab05abf919c429a1784139d26c416e0ed..92bef089e417bb9e3387930a35d31151f9ff4fbe 100644 (file)
@@ -290,6 +290,7 @@ HEIMDAL_KRB5_OBJ_FILES = \
        $(heimdalsrcdir)/lib/krb5/free_host_realm.o \
        $(heimdalsrcdir)/lib/krb5/generate_seq_number.o \
        $(heimdalsrcdir)/lib/krb5/generate_subkey.o \
+       $(heimdalsrcdir)/lib/krb5/get_addrs.o \
        $(heimdalsrcdir)/lib/krb5/get_cred.o \
        $(heimdalsrcdir)/lib/krb5/get_default_principal.o \
        $(heimdalsrcdir)/lib/krb5/get_default_realm.o \
index b41e3c02718c6c1ee3c53f7a3644af592da73594..8a09a91f3ebb530b4ef9b2a1446afbce3998750d 100644 (file)
 #include "lib/socket/netif.h"
 #include "param/param.h"
 
-/**
-  get the list of IP addresses for configured interfaces
-*/
-krb5_error_code KRB5_LIB_FUNCTION krb5_get_all_client_addrs(krb5_context context, krb5_addresses *res)
-{
-       int i;
-       struct interface *ifaces;
-
-       load_interfaces(NULL, lp_interfaces(global_loadparm), &ifaces);
-
-       res->len = iface_count(ifaces);
-       res->val = malloc_array_p(HostAddress, res->len);
-       if (res->val == NULL) {
-               talloc_free(ifaces);
-               return ENOMEM;
-       }
-       for (i=0;i<res->len;i++) {
-               const char *ip = iface_n_ip(ifaces, i);
-               res->val[i].addr_type = AF_INET;
-               res->val[i].address.length = 4;
-               res->val[i].address.data = malloc(4);
-               if (res->val[i].address.data == NULL) {
-                       talloc_free(ifaces);
-                       return ENOMEM;
-               }
-               ((struct in_addr *)res->val[i].address.data)->s_addr = inet_addr(ip);
-       }
-
-       talloc_free(ifaces);
-
-       return 0;
-}
-
 #include "heimdal/lib/krb5/krb5_locl.h"
 
 const krb5_cc_ops krb5_scc_ops = {