1b528cefcSMark Murray /* 2*adb0ddaeSAssar Westerlund * Copyright (c) 1997 - 2001 Kungliga Tekniska H�gskolan 3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden). 4b528cefcSMark Murray * All rights reserved. 5b528cefcSMark Murray * 6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without 7b528cefcSMark Murray * modification, are permitted provided that the following conditions 8b528cefcSMark Murray * are met: 9b528cefcSMark Murray * 10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright 11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer. 12b528cefcSMark Murray * 13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright 14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the 15b528cefcSMark Murray * documentation and/or other materials provided with the distribution. 16b528cefcSMark Murray * 17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors 18b528cefcSMark Murray * may be used to endorse or promote products derived from this software 19b528cefcSMark Murray * without specific prior written permission. 20b528cefcSMark Murray * 21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31b528cefcSMark Murray * SUCH DAMAGE. 32b528cefcSMark Murray */ 33b528cefcSMark Murray 34b528cefcSMark Murray #include "krb5_locl.h" 35b528cefcSMark Murray 36*adb0ddaeSAssar Westerlund RCSID("$Id: get_addrs.c,v 1.41 2001/05/14 06:14:46 assar Exp $"); 37b528cefcSMark Murray 38b528cefcSMark Murray #ifdef __osf__ 39b528cefcSMark Murray /* hate */ 40b528cefcSMark Murray struct rtentry; 41b528cefcSMark Murray struct mbuf; 42b528cefcSMark Murray #endif 43b528cefcSMark Murray #ifdef HAVE_NET_IF_H 44b528cefcSMark Murray #include <net/if.h> 45b528cefcSMark Murray #endif 465e9cd1aeSAssar Westerlund #include <ifaddrs.h> 47b528cefcSMark Murray 48b528cefcSMark Murray static krb5_error_code 49*adb0ddaeSAssar Westerlund gethostname_fallback (krb5_context context, krb5_addresses *res) 50b528cefcSMark Murray { 51*adb0ddaeSAssar Westerlund krb5_error_code ret; 52b528cefcSMark Murray char hostname[MAXHOSTNAMELEN]; 53b528cefcSMark Murray struct hostent *hostent; 54b528cefcSMark Murray 55*adb0ddaeSAssar Westerlund if (gethostname (hostname, sizeof(hostname))) { 56*adb0ddaeSAssar Westerlund ret = errno; 57*adb0ddaeSAssar Westerlund krb5_set_error_string (context, "gethostname: %s", strerror(ret)); 58*adb0ddaeSAssar Westerlund return ret; 59*adb0ddaeSAssar Westerlund } 60b528cefcSMark Murray hostent = roken_gethostbyname (hostname); 61*adb0ddaeSAssar Westerlund if (hostent == NULL) { 62*adb0ddaeSAssar Westerlund ret = errno; 63*adb0ddaeSAssar Westerlund krb5_set_error_string (context, "gethostbyname %s: %s", 64*adb0ddaeSAssar Westerlund hostname, strerror(ret)); 65*adb0ddaeSAssar Westerlund return ret; 66*adb0ddaeSAssar Westerlund } 67b528cefcSMark Murray res->len = 1; 68b528cefcSMark Murray res->val = malloc (sizeof(*res->val)); 69*adb0ddaeSAssar Westerlund if (res->val == NULL) { 70*adb0ddaeSAssar Westerlund krb5_set_error_string(context, "malloc: out of memory"); 71b528cefcSMark Murray return ENOMEM; 72*adb0ddaeSAssar Westerlund } 73b528cefcSMark Murray res->val[0].addr_type = hostent->h_addrtype; 74b528cefcSMark Murray res->val[0].address.data = NULL; 75b528cefcSMark Murray res->val[0].address.length = 0; 76*adb0ddaeSAssar Westerlund ret = krb5_data_copy (&res->val[0].address, 77b528cefcSMark Murray hostent->h_addr, 78b528cefcSMark Murray hostent->h_length); 79*adb0ddaeSAssar Westerlund if (ret) { 80b528cefcSMark Murray free (res->val); 81*adb0ddaeSAssar Westerlund return ret; 82b528cefcSMark Murray } 83b528cefcSMark Murray return 0; 84b528cefcSMark Murray } 85b528cefcSMark Murray 86b528cefcSMark Murray enum { 87b528cefcSMark Murray LOOP = 1, /* do include loopback interfaces */ 88b528cefcSMark Murray LOOP_IF_NONE = 2, /* include loopback if no other if's */ 89b528cefcSMark Murray EXTRA_ADDRESSES = 4, /* include extra addresses */ 90b528cefcSMark Murray SCAN_INTERFACES = 8 /* scan interfaces for addresses */ 91b528cefcSMark Murray }; 92b528cefcSMark Murray 93b528cefcSMark Murray /* 94b528cefcSMark Murray * Try to figure out the addresses of all configured interfaces with a 95b528cefcSMark Murray * lot of magic ioctls. 96b528cefcSMark Murray */ 97b528cefcSMark Murray 98b528cefcSMark Murray static krb5_error_code 995e9cd1aeSAssar Westerlund find_all_addresses (krb5_context context, krb5_addresses *res, int flags) 100b528cefcSMark Murray { 101b528cefcSMark Murray struct sockaddr sa_zero; 1025e9cd1aeSAssar Westerlund struct ifaddrs *ifa0, *ifa; 1035e9cd1aeSAssar Westerlund krb5_error_code ret = ENXIO; 1045e9cd1aeSAssar Westerlund int num, idx; 105b528cefcSMark Murray 106b528cefcSMark Murray res->val = NULL; 107b528cefcSMark Murray 108*adb0ddaeSAssar Westerlund if (getifaddrs(&ifa0) == -1) { 109*adb0ddaeSAssar Westerlund ret = errno; 110*adb0ddaeSAssar Westerlund krb5_set_error_string(context, "getifaddrs: %s", strerror(ret)); 111*adb0ddaeSAssar Westerlund return (ret); 112*adb0ddaeSAssar Westerlund } 1135e9cd1aeSAssar Westerlund 114b528cefcSMark Murray memset(&sa_zero, 0, sizeof(sa_zero)); 115b528cefcSMark Murray 1165e9cd1aeSAssar Westerlund /* First, count all the ifaddrs. */ 1175e9cd1aeSAssar Westerlund for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++) 1185e9cd1aeSAssar Westerlund /* nothing */; 119b528cefcSMark Murray 1205e9cd1aeSAssar Westerlund if (num == 0) { 1215e9cd1aeSAssar Westerlund freeifaddrs(ifa0); 122*adb0ddaeSAssar Westerlund krb5_set_error_string(context, "no addresses found"); 1235e9cd1aeSAssar Westerlund return (ENXIO); 124b528cefcSMark Murray } 125b528cefcSMark Murray 1265e9cd1aeSAssar Westerlund /* Allocate storage for them. */ 127b528cefcSMark Murray res->val = calloc(num, sizeof(*res->val)); 128b528cefcSMark Murray if (res->val == NULL) { 1295e9cd1aeSAssar Westerlund freeifaddrs(ifa0); 130*adb0ddaeSAssar Westerlund krb5_set_error_string (context, "malloc: out of memory"); 1315e9cd1aeSAssar Westerlund return (ENOMEM); 132b528cefcSMark Murray } 133b528cefcSMark Murray 1345e9cd1aeSAssar Westerlund /* Now traverse the list. */ 1355e9cd1aeSAssar Westerlund for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) { 1365e9cd1aeSAssar Westerlund if ((ifa->ifa_flags & IFF_UP) == 0) 1375e9cd1aeSAssar Westerlund continue; 1385e9cd1aeSAssar Westerlund if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 1395e9cd1aeSAssar Westerlund continue; 1405e9cd1aeSAssar Westerlund if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 1415e9cd1aeSAssar Westerlund continue; 142b528cefcSMark Murray 1435e9cd1aeSAssar Westerlund if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) { 1445e9cd1aeSAssar Westerlund /* We'll deal with the LOOP_IF_NONE case later. */ 1455e9cd1aeSAssar Westerlund if ((flags & LOOP) == 0) 1465e9cd1aeSAssar Westerlund continue; 147b528cefcSMark Murray } 148b528cefcSMark Murray 149*adb0ddaeSAssar Westerlund ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]); 1505e9cd1aeSAssar Westerlund if (ret) { 1515e9cd1aeSAssar Westerlund /* 1525e9cd1aeSAssar Westerlund * The most likely error here is going to be "Program 1535e9cd1aeSAssar Westerlund * lacks support for address type". This is no big 1545e9cd1aeSAssar Westerlund * deal -- just continue, and we'll listen on the 1555e9cd1aeSAssar Westerlund * addresses who's type we *do* support. 1565e9cd1aeSAssar Westerlund */ 157b528cefcSMark Murray continue; 1585e9cd1aeSAssar Westerlund } 1595e9cd1aeSAssar Westerlund idx++; 1605e9cd1aeSAssar Westerlund } 1615e9cd1aeSAssar Westerlund 1625e9cd1aeSAssar Westerlund /* 1635e9cd1aeSAssar Westerlund * If no addresses were found, and LOOP_IF_NONE is set, then find 1645e9cd1aeSAssar Westerlund * the loopback addresses and add them to our list. 1655e9cd1aeSAssar Westerlund */ 1665e9cd1aeSAssar Westerlund if ((flags & LOOP_IF_NONE) != 0 && idx == 0) { 1675e9cd1aeSAssar Westerlund for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { 1685e9cd1aeSAssar Westerlund if ((ifa->ifa_flags & IFF_UP) == 0) 169b528cefcSMark Murray continue; 1705e9cd1aeSAssar Westerlund if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 1715e9cd1aeSAssar Westerlund continue; 1725e9cd1aeSAssar Westerlund if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 173b528cefcSMark Murray continue; 174b528cefcSMark Murray 1755e9cd1aeSAssar Westerlund if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) { 176*adb0ddaeSAssar Westerlund ret = krb5_sockaddr2address(context, 177*adb0ddaeSAssar Westerlund ifa->ifa_addr, &res->val[idx]); 1785e9cd1aeSAssar Westerlund if (ret) { 1795e9cd1aeSAssar Westerlund /* 1805e9cd1aeSAssar Westerlund * See comment above. 1815e9cd1aeSAssar Westerlund */ 1825e9cd1aeSAssar Westerlund continue; 1835e9cd1aeSAssar Westerlund } 1845e9cd1aeSAssar Westerlund idx++; 1855e9cd1aeSAssar Westerlund } 1865e9cd1aeSAssar Westerlund } 1875e9cd1aeSAssar Westerlund } 1885e9cd1aeSAssar Westerlund 1895e9cd1aeSAssar Westerlund freeifaddrs(ifa0); 190b528cefcSMark Murray if (ret) 191b528cefcSMark Murray free(res->val); 1925e9cd1aeSAssar Westerlund else 1935e9cd1aeSAssar Westerlund res->len = idx; /* Now a count. */ 1945e9cd1aeSAssar Westerlund return (ret); 195b528cefcSMark Murray } 196b528cefcSMark Murray 197b528cefcSMark Murray static krb5_error_code 198b528cefcSMark Murray get_addrs_int (krb5_context context, krb5_addresses *res, int flags) 199b528cefcSMark Murray { 200b528cefcSMark Murray krb5_error_code ret = -1; 201b528cefcSMark Murray 202b528cefcSMark Murray if (flags & SCAN_INTERFACES) { 2035e9cd1aeSAssar Westerlund ret = find_all_addresses (context, res, flags); 204b528cefcSMark Murray if(ret || res->len == 0) 205*adb0ddaeSAssar Westerlund ret = gethostname_fallback (context, res); 206b528cefcSMark Murray } else 207b528cefcSMark Murray ret = 0; 208b528cefcSMark Murray 209b528cefcSMark Murray if(ret == 0 && (flags & EXTRA_ADDRESSES)) { 210b528cefcSMark Murray /* append user specified addresses */ 211b528cefcSMark Murray krb5_addresses a; 212b528cefcSMark Murray ret = krb5_get_extra_addresses(context, &a); 213b528cefcSMark Murray if(ret) { 214b528cefcSMark Murray krb5_free_addresses(context, res); 215b528cefcSMark Murray return ret; 216b528cefcSMark Murray } 217b528cefcSMark Murray ret = krb5_append_addresses(context, res, &a); 218b528cefcSMark Murray if(ret) { 219b528cefcSMark Murray krb5_free_addresses(context, res); 220b528cefcSMark Murray return ret; 221b528cefcSMark Murray } 222b528cefcSMark Murray krb5_free_addresses(context, &a); 223b528cefcSMark Murray } 224b528cefcSMark Murray return ret; 225b528cefcSMark Murray } 226b528cefcSMark Murray 227b528cefcSMark Murray /* 228b528cefcSMark Murray * Try to get all addresses, but return the one corresponding to 229b528cefcSMark Murray * `hostname' if we fail. 230b528cefcSMark Murray * 231b528cefcSMark Murray * Only include loopback address if there are no other. 232b528cefcSMark Murray */ 233b528cefcSMark Murray 234b528cefcSMark Murray krb5_error_code 235b528cefcSMark Murray krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res) 236b528cefcSMark Murray { 237b528cefcSMark Murray int flags = LOOP_IF_NONE | EXTRA_ADDRESSES; 238b528cefcSMark Murray 239b528cefcSMark Murray if (context->scan_interfaces) 240b528cefcSMark Murray flags |= SCAN_INTERFACES; 241b528cefcSMark Murray 242b528cefcSMark Murray return get_addrs_int (context, res, flags); 243b528cefcSMark Murray } 244b528cefcSMark Murray 245b528cefcSMark Murray /* 246b528cefcSMark Murray * Try to get all local addresses that a server should listen to. 247b528cefcSMark Murray * If that fails, we return the address corresponding to `hostname'. 248b528cefcSMark Murray */ 249b528cefcSMark Murray 250b528cefcSMark Murray krb5_error_code 251b528cefcSMark Murray krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res) 252b528cefcSMark Murray { 253b528cefcSMark Murray return get_addrs_int (context, res, LOOP | SCAN_INTERFACES); 254b528cefcSMark Murray } 255