1 /* $NetBSD: get_addrs.c,v 1.1.1.1 2011/04/13 18:15:33 elric Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "krb5_locl.h" 37 38 #ifdef __osf__ 39 /* hate */ 40 struct rtentry; 41 struct mbuf; 42 #endif 43 #ifdef HAVE_NET_IF_H 44 #include <net/if.h> 45 #endif 46 #include <ifaddrs.h> 47 48 static krb5_error_code 49 gethostname_fallback (krb5_context context, krb5_addresses *res) 50 { 51 krb5_error_code ret; 52 char hostname[MAXHOSTNAMELEN]; 53 struct hostent *hostent; 54 55 if (gethostname (hostname, sizeof(hostname))) { 56 ret = errno; 57 krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret)); 58 return ret; 59 } 60 hostent = roken_gethostbyname (hostname); 61 if (hostent == NULL) { 62 ret = errno; 63 krb5_set_error_message (context, ret, "gethostbyname %s: %s", 64 hostname, strerror(ret)); 65 return ret; 66 } 67 res->len = 1; 68 res->val = malloc (sizeof(*res->val)); 69 if (res->val == NULL) { 70 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 71 return ENOMEM; 72 } 73 res->val[0].addr_type = hostent->h_addrtype; 74 res->val[0].address.data = NULL; 75 res->val[0].address.length = 0; 76 ret = krb5_data_copy (&res->val[0].address, 77 hostent->h_addr, 78 hostent->h_length); 79 if (ret) { 80 free (res->val); 81 return ret; 82 } 83 return 0; 84 } 85 86 enum { 87 LOOP = 1, /* do include loopback addrs */ 88 LOOP_IF_NONE = 2, /* include loopback addrs if no others */ 89 EXTRA_ADDRESSES = 4, /* include extra addresses */ 90 SCAN_INTERFACES = 8 /* scan interfaces for addresses */ 91 }; 92 93 /* 94 * Try to figure out the addresses of all configured interfaces with a 95 * lot of magic ioctls. 96 */ 97 98 static krb5_error_code 99 find_all_addresses (krb5_context context, krb5_addresses *res, int flags) 100 { 101 struct sockaddr sa_zero; 102 struct ifaddrs *ifa0, *ifa; 103 krb5_error_code ret = ENXIO; 104 unsigned int num, idx; 105 krb5_addresses ignore_addresses; 106 107 if (getifaddrs(&ifa0) == -1) { 108 ret = errno; 109 krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret)); 110 return (ret); 111 } 112 113 memset(&sa_zero, 0, sizeof(sa_zero)); 114 115 /* First, count all the ifaddrs. */ 116 for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++) 117 /* nothing */; 118 119 if (num == 0) { 120 freeifaddrs(ifa0); 121 krb5_set_error_message(context, ENXIO, N_("no addresses found", "")); 122 return (ENXIO); 123 } 124 125 if (flags & EXTRA_ADDRESSES) { 126 /* we'll remove the addresses we don't care about */ 127 ret = krb5_get_ignore_addresses(context, &ignore_addresses); 128 if(ret) 129 return ret; 130 } 131 132 /* Allocate storage for them. */ 133 res->val = calloc(num, sizeof(*res->val)); 134 if (res->val == NULL) { 135 krb5_free_addresses(context, &ignore_addresses); 136 freeifaddrs(ifa0); 137 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 138 return ENOMEM; 139 } 140 141 /* Now traverse the list. */ 142 for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) { 143 if ((ifa->ifa_flags & IFF_UP) == 0) 144 continue; 145 if (ifa->ifa_addr == NULL) 146 continue; 147 if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 148 continue; 149 if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 150 continue; 151 if (krb5_sockaddr_is_loopback(ifa->ifa_addr) && (flags & LOOP) == 0) 152 /* We'll deal with the LOOP_IF_NONE case later. */ 153 continue; 154 155 ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]); 156 if (ret) { 157 /* 158 * The most likely error here is going to be "Program 159 * lacks support for address type". This is no big 160 * deal -- just continue, and we'll listen on the 161 * addresses who's type we *do* support. 162 */ 163 continue; 164 } 165 /* possibly skip this address? */ 166 if((flags & EXTRA_ADDRESSES) && 167 krb5_address_search(context, &res->val[idx], &ignore_addresses)) { 168 krb5_free_address(context, &res->val[idx]); 169 flags &= ~LOOP_IF_NONE; /* we actually found an address, 170 so don't add any loop-back 171 addresses */ 172 continue; 173 } 174 175 idx++; 176 } 177 178 /* 179 * If no addresses were found, and LOOP_IF_NONE is set, then find 180 * the loopback addresses and add them to our list. 181 */ 182 if ((flags & LOOP_IF_NONE) != 0 && idx == 0) { 183 for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { 184 if ((ifa->ifa_flags & IFF_UP) == 0) 185 continue; 186 if (ifa->ifa_addr == NULL) 187 continue; 188 if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0) 189 continue; 190 if (krb5_sockaddr_uninteresting(ifa->ifa_addr)) 191 continue; 192 if (!krb5_sockaddr_is_loopback(ifa->ifa_addr)) 193 continue; 194 if ((ifa->ifa_flags & IFF_LOOPBACK) == 0) 195 /* Presumably loopback addrs are only used on loopback ifs! */ 196 continue; 197 ret = krb5_sockaddr2address(context, 198 ifa->ifa_addr, &res->val[idx]); 199 if (ret) 200 continue; /* We don't consider this failure fatal */ 201 if((flags & EXTRA_ADDRESSES) && 202 krb5_address_search(context, &res->val[idx], 203 &ignore_addresses)) { 204 krb5_free_address(context, &res->val[idx]); 205 continue; 206 } 207 idx++; 208 } 209 } 210 211 if (flags & EXTRA_ADDRESSES) 212 krb5_free_addresses(context, &ignore_addresses); 213 freeifaddrs(ifa0); 214 if (ret) { 215 free(res->val); 216 res->val = NULL; 217 } else 218 res->len = idx; /* Now a count. */ 219 return (ret); 220 } 221 222 static krb5_error_code 223 get_addrs_int (krb5_context context, krb5_addresses *res, int flags) 224 { 225 krb5_error_code ret = -1; 226 227 res->len = 0; 228 res->val = NULL; 229 230 if (flags & SCAN_INTERFACES) { 231 ret = find_all_addresses (context, res, flags); 232 if(ret || res->len == 0) 233 ret = gethostname_fallback (context, res); 234 } else { 235 ret = 0; 236 } 237 238 if(ret == 0 && (flags & EXTRA_ADDRESSES)) { 239 krb5_addresses a; 240 /* append user specified addresses */ 241 ret = krb5_get_extra_addresses(context, &a); 242 if(ret) { 243 krb5_free_addresses(context, res); 244 return ret; 245 } 246 ret = krb5_append_addresses(context, res, &a); 247 if(ret) { 248 krb5_free_addresses(context, res); 249 return ret; 250 } 251 krb5_free_addresses(context, &a); 252 } 253 if(res->len == 0) { 254 free(res->val); 255 res->val = NULL; 256 } 257 return ret; 258 } 259 260 /* 261 * Try to get all addresses, but return the one corresponding to 262 * `hostname' if we fail. 263 * 264 * Only include loopback address if there are no other. 265 */ 266 267 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 268 krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res) 269 { 270 int flags = LOOP_IF_NONE | EXTRA_ADDRESSES; 271 272 if (context->scan_interfaces) 273 flags |= SCAN_INTERFACES; 274 275 return get_addrs_int (context, res, flags); 276 } 277 278 /* 279 * Try to get all local addresses that a server should listen to. 280 * If that fails, we return the address corresponding to `hostname'. 281 */ 282 283 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 284 krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res) 285 { 286 return get_addrs_int (context, res, LOOP | SCAN_INTERFACES); 287 } 288