xref: /minix3/crypto/external/bsd/heimdal/dist/lib/krb5/get_addrs.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
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