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