155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2002 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm 3655682Smarkm#ifdef __osf__ 3755682Smarkm/* hate */ 3855682Smarkmstruct rtentry; 3955682Smarkmstruct mbuf; 4055682Smarkm#endif 4155682Smarkm#ifdef HAVE_NET_IF_H 4255682Smarkm#include <net/if.h> 4355682Smarkm#endif 4472445Sassar#include <ifaddrs.h> 4555682Smarkm 4655682Smarkmstatic krb5_error_code 4778527Sassargethostname_fallback (krb5_context context, krb5_addresses *res) 4855682Smarkm{ 4978527Sassar krb5_error_code ret; 5072445Sassar char hostname[MAXHOSTNAMELEN]; 5172445Sassar struct hostent *hostent; 5255682Smarkm 5378527Sassar if (gethostname (hostname, sizeof(hostname))) { 5478527Sassar ret = errno; 55233294Sstas krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret)); 5678527Sassar return ret; 5778527Sassar } 5872445Sassar hostent = roken_gethostbyname (hostname); 5978527Sassar if (hostent == NULL) { 6078527Sassar ret = errno; 61233294Sstas krb5_set_error_message (context, ret, "gethostbyname %s: %s", 62233294Sstas hostname, strerror(ret)); 6378527Sassar return ret; 6478527Sassar } 6572445Sassar res->len = 1; 6672445Sassar res->val = malloc (sizeof(*res->val)); 6778527Sassar if (res->val == NULL) { 68233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 6972445Sassar return ENOMEM; 7078527Sassar } 7172445Sassar res->val[0].addr_type = hostent->h_addrtype; 7272445Sassar res->val[0].address.data = NULL; 7372445Sassar res->val[0].address.length = 0; 7478527Sassar ret = krb5_data_copy (&res->val[0].address, 7572445Sassar hostent->h_addr, 7672445Sassar hostent->h_length); 7778527Sassar if (ret) { 7872445Sassar free (res->val); 7978527Sassar return ret; 8072445Sassar } 8172445Sassar return 0; 8255682Smarkm} 8355682Smarkm 8455682Smarkmenum { 85233294Sstas LOOP = 1, /* do include loopback addrs */ 86233294Sstas LOOP_IF_NONE = 2, /* include loopback addrs if no others */ 8755682Smarkm EXTRA_ADDRESSES = 4, /* include extra addresses */ 8855682Smarkm SCAN_INTERFACES = 8 /* scan interfaces for addresses */ 8955682Smarkm}; 9055682Smarkm 9155682Smarkm/* 9255682Smarkm * Try to figure out the addresses of all configured interfaces with a 9355682Smarkm * lot of magic ioctls. 9455682Smarkm */ 9555682Smarkm 9655682Smarkmstatic krb5_error_code 9772445Sassarfind_all_addresses (krb5_context context, krb5_addresses *res, int flags) 9855682Smarkm{ 9972445Sassar struct sockaddr sa_zero; 10072445Sassar struct ifaddrs *ifa0, *ifa; 101233294Sstas krb5_error_code ret = ENXIO; 102233294Sstas unsigned int num, idx; 10390926Snectar krb5_addresses ignore_addresses; 10455682Smarkm 10578527Sassar if (getifaddrs(&ifa0) == -1) { 10678527Sassar ret = errno; 107233294Sstas krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret)); 10878527Sassar return (ret); 10978527Sassar } 11055682Smarkm 11172445Sassar memset(&sa_zero, 0, sizeof(sa_zero)); 11255682Smarkm 11372445Sassar /* First, count all the ifaddrs. */ 11472445Sassar for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++) 11572445Sassar /* nothing */; 11655682Smarkm 11772445Sassar if (num == 0) { 11872445Sassar freeifaddrs(ifa0); 119233294Sstas krb5_set_error_message(context, ENXIO, N_("no addresses found", "")); 12072445Sassar return (ENXIO); 12172445Sassar } 12255682Smarkm 12390926Snectar if (flags & EXTRA_ADDRESSES) { 12490926Snectar /* we'll remove the addresses we don't care about */ 12590926Snectar ret = krb5_get_ignore_addresses(context, &ignore_addresses); 12690926Snectar if(ret) 12790926Snectar return ret; 12890926Snectar } 12990926Snectar 13072445Sassar /* Allocate storage for them. */ 13172445Sassar res->val = calloc(num, sizeof(*res->val)); 13272445Sassar if (res->val == NULL) { 13390926Snectar krb5_free_addresses(context, &ignore_addresses); 13472445Sassar freeifaddrs(ifa0); 135233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 136233294Sstas return ENOMEM; 13772445Sassar } 13855682Smarkm 13972445Sassar /* Now traverse the list. */ 14072445Sassar for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) { 14172445Sassar if ((ifa->ifa_flags & IFF_UP) == 0) 14272445Sassar continue; 143120945Snectar if (ifa->ifa_addr == NULL) 144120945Snectar continue; 14572445Sassar if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 14672445Sassar continue; 14772445Sassar if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 14872445Sassar continue; 149233294Sstas if (krb5_sockaddr_is_loopback(ifa->ifa_addr) && (flags & LOOP) == 0) 15072445Sassar /* We'll deal with the LOOP_IF_NONE case later. */ 151233294Sstas continue; 15255682Smarkm 15378527Sassar ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]); 15472445Sassar if (ret) { 15572445Sassar /* 15672445Sassar * The most likely error here is going to be "Program 15772445Sassar * lacks support for address type". This is no big 15872445Sassar * deal -- just continue, and we'll listen on the 15972445Sassar * addresses who's type we *do* support. 16072445Sassar */ 16172445Sassar continue; 16272445Sassar } 16390926Snectar /* possibly skip this address? */ 164233294Sstas if((flags & EXTRA_ADDRESSES) && 16590926Snectar krb5_address_search(context, &res->val[idx], &ignore_addresses)) { 16690926Snectar krb5_free_address(context, &res->val[idx]); 16790926Snectar flags &= ~LOOP_IF_NONE; /* we actually found an address, 16890926Snectar so don't add any loop-back 16990926Snectar addresses */ 17090926Snectar continue; 17190926Snectar } 17290926Snectar 17372445Sassar idx++; 17472445Sassar } 17555682Smarkm 17672445Sassar /* 17772445Sassar * If no addresses were found, and LOOP_IF_NONE is set, then find 17872445Sassar * the loopback addresses and add them to our list. 17972445Sassar */ 18072445Sassar if ((flags & LOOP_IF_NONE) != 0 && idx == 0) { 18172445Sassar for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { 18272445Sassar if ((ifa->ifa_flags & IFF_UP) == 0) 18372445Sassar continue; 184120945Snectar if (ifa->ifa_addr == NULL) 185120945Snectar continue; 18672445Sassar if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 18772445Sassar continue; 18872445Sassar if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 18972445Sassar continue; 190233294Sstas if (!krb5_sockaddr_is_loopback(ifa->ifa_addr)) 191233294Sstas continue; 192233294Sstas if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) 193233294Sstas /* Presumably loopback addrs are only used on loopback ifs! */ 194233294Sstas continue; 195233294Sstas ret = krb5_sockaddr2address(context, 196233294Sstas ifa->ifa_addr, &res->val[idx]); 197233294Sstas if (ret) 198233294Sstas continue; /* We don't consider this failure fatal */ 199233294Sstas if((flags & EXTRA_ADDRESSES) && 200233294Sstas krb5_address_search(context, &res->val[idx], 201233294Sstas &ignore_addresses)) { 202233294Sstas krb5_free_address(context, &res->val[idx]); 203233294Sstas continue; 20472445Sassar } 205233294Sstas idx++; 20672445Sassar } 20772445Sassar } 20855682Smarkm 20990926Snectar if (flags & EXTRA_ADDRESSES) 21090926Snectar krb5_free_addresses(context, &ignore_addresses); 21172445Sassar freeifaddrs(ifa0); 212233294Sstas if (ret) { 21372445Sassar free(res->val); 214233294Sstas res->val = NULL; 215233294Sstas } else 21672445Sassar res->len = idx; /* Now a count. */ 21772445Sassar return (ret); 21855682Smarkm} 21955682Smarkm 22055682Smarkmstatic krb5_error_code 22155682Smarkmget_addrs_int (krb5_context context, krb5_addresses *res, int flags) 22255682Smarkm{ 22355682Smarkm krb5_error_code ret = -1; 22455682Smarkm 225233294Sstas res->len = 0; 226233294Sstas res->val = NULL; 227233294Sstas 22855682Smarkm if (flags & SCAN_INTERFACES) { 22972445Sassar ret = find_all_addresses (context, res, flags); 23055682Smarkm if(ret || res->len == 0) 23178527Sassar ret = gethostname_fallback (context, res); 232102644Snectar } else { 23355682Smarkm ret = 0; 234102644Snectar } 23555682Smarkm 23655682Smarkm if(ret == 0 && (flags & EXTRA_ADDRESSES)) { 23790926Snectar krb5_addresses a; 23855682Smarkm /* append user specified addresses */ 23955682Smarkm ret = krb5_get_extra_addresses(context, &a); 24055682Smarkm if(ret) { 24155682Smarkm krb5_free_addresses(context, res); 24255682Smarkm return ret; 24355682Smarkm } 24455682Smarkm ret = krb5_append_addresses(context, res, &a); 24555682Smarkm if(ret) { 24655682Smarkm krb5_free_addresses(context, res); 24755682Smarkm return ret; 24855682Smarkm } 24955682Smarkm krb5_free_addresses(context, &a); 25055682Smarkm } 25190926Snectar if(res->len == 0) { 25290926Snectar free(res->val); 25390926Snectar res->val = NULL; 25490926Snectar } 25555682Smarkm return ret; 25655682Smarkm} 25755682Smarkm 25855682Smarkm/* 25955682Smarkm * Try to get all addresses, but return the one corresponding to 26055682Smarkm * `hostname' if we fail. 26155682Smarkm * 26255682Smarkm * Only include loopback address if there are no other. 26355682Smarkm */ 26455682Smarkm 265233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 26655682Smarkmkrb5_get_all_client_addrs (krb5_context context, krb5_addresses *res) 26755682Smarkm{ 26855682Smarkm int flags = LOOP_IF_NONE | EXTRA_ADDRESSES; 26955682Smarkm 27055682Smarkm if (context->scan_interfaces) 27155682Smarkm flags |= SCAN_INTERFACES; 27255682Smarkm 27355682Smarkm return get_addrs_int (context, res, flags); 27455682Smarkm} 27555682Smarkm 27655682Smarkm/* 27755682Smarkm * Try to get all local addresses that a server should listen to. 27855682Smarkm * If that fails, we return the address corresponding to `hostname'. 27955682Smarkm */ 28055682Smarkm 281233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 28255682Smarkmkrb5_get_all_server_addrs (krb5_context context, krb5_addresses *res) 28355682Smarkm{ 28455682Smarkm return get_addrs_int (context, res, LOOP | SCAN_INTERFACES); 28555682Smarkm} 286