root/source4/heimdal/lib/krb5/get_addrs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gethostname_fallback
  2. find_all_addresses
  3. get_addrs_int
  4. krb5_get_all_client_addrs
  5. krb5_get_all_server_addrs

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

/* [<][>][^][v][top][bottom][index][help] */