2
* Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
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.
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.
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
34
#include "krb5_locl.h"
36
RCSID("$Id: get_addrs.c 23815 2008-09-13 09:21:03Z lha $");
50
static krb5_error_code
51
gethostname_fallback (krb5_context context, krb5_addresses *res)
54
char hostname[MAXHOSTNAMELEN];
55
struct hostent *hostent;
57
if (gethostname (hostname, sizeof(hostname))) {
59
krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret));
62
hostent = roken_gethostbyname (hostname);
63
if (hostent == NULL) {
65
krb5_set_error_message (context, ret, "gethostbyname %s: %s",
66
hostname, strerror(ret));
70
res->val = malloc (sizeof(*res->val));
71
if (res->val == NULL) {
72
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
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,
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 */
96
* Try to figure out the addresses of all configured interfaces with a
97
* lot of magic ioctls.
100
static krb5_error_code
101
find_all_addresses (krb5_context context, krb5_addresses *res, int flags)
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;
111
if (getifaddrs(&ifa0) == -1) {
113
krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret));
117
memset(&sa_zero, 0, sizeof(sa_zero));
119
/* First, count all the ifaddrs. */
120
for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++)
125
krb5_set_error_message(context, ENXIO, N_("no addresses found", ""));
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);
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);
141
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
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)
149
if (ifa->ifa_addr == NULL)
151
if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
153
if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
155
if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
156
/* We'll deal with the LOOP_IF_NONE case later. */
157
if ((flags & LOOP) == 0)
161
ret = krb5_sockaddr2address(context, ifa->ifa_addr, &res->val[idx]);
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.
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
185
* If no addresses were found, and LOOP_IF_NONE is set, then find
186
* the loopback addresses and add them to our list.
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)
192
if (ifa->ifa_addr == NULL)
194
if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
196
if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
199
if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
200
ret = krb5_sockaddr2address(context,
201
ifa->ifa_addr, &res->val[idx]);
208
if((flags & EXTRA_ADDRESSES) &&
209
krb5_address_search(context, &res->val[idx],
210
&ignore_addresses)) {
211
krb5_free_address(context, &res->val[idx]);
219
if (flags & EXTRA_ADDRESSES)
220
krb5_free_addresses(context, &ignore_addresses);
226
res->len = idx; /* Now a count. */
230
static krb5_error_code
231
get_addrs_int (krb5_context context, krb5_addresses *res, int flags)
233
krb5_error_code ret = -1;
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);
245
if(ret == 0 && (flags & EXTRA_ADDRESSES)) {
247
/* append user specified addresses */
248
ret = krb5_get_extra_addresses(context, &a);
250
krb5_free_addresses(context, res);
253
ret = krb5_append_addresses(context, res, &a);
255
krb5_free_addresses(context, res);
258
krb5_free_addresses(context, &a);
268
* Try to get all addresses, but return the one corresponding to
269
* `hostname' if we fail.
271
* Only include loopback address if there are no other.
274
krb5_error_code KRB5_LIB_FUNCTION
275
krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res)
277
int flags = LOOP_IF_NONE | EXTRA_ADDRESSES;
279
if (context->scan_interfaces)
280
flags |= SCAN_INTERFACES;
282
return get_addrs_int (context, res, flags);
286
* Try to get all local addresses that a server should listen to.
287
* If that fails, we return the address corresponding to `hostname'.
290
krb5_error_code KRB5_LIB_FUNCTION
291
krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res)
293
return get_addrs_int (context, res, LOOP | SCAN_INTERFACES);