• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/heimdal/lib/krb5/
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#ifdef __osf__
37/* hate */
38struct rtentry;
39struct mbuf;
40#endif
41#ifdef HAVE_NET_IF_H
42#include <net/if.h>
43#endif
44#include <ifaddrs.h>
45
46static krb5_error_code
47gethostname_fallback (krb5_context context, krb5_addresses *res)
48{
49    krb5_error_code ret;
50    char hostname[MAXHOSTNAMELEN];
51    struct hostent *hostent;
52
53    if (gethostname (hostname, sizeof(hostname))) {
54	ret = errno;
55	krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret));
56	return ret;
57    }
58    hostent = roken_gethostbyname (hostname);
59    if (hostent == NULL) {
60	ret = errno;
61	krb5_set_error_message (context, ret, "gethostbyname %s: %s",
62				hostname, strerror(ret));
63	return ret;
64    }
65    res->len = 1;
66    res->val = malloc (sizeof(*res->val));
67    if (res->val == NULL) {
68	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
69	return ENOMEM;
70    }
71    res->val[0].addr_type = hostent->h_addrtype;
72    res->val[0].address.data = NULL;
73    res->val[0].address.length = 0;
74    ret = krb5_data_copy (&res->val[0].address,
75			  hostent->h_addr,
76			  hostent->h_length);
77    if (ret) {
78	free (res->val);
79	return ret;
80    }
81    return 0;
82}
83
84enum {
85    LOOP            = 1,	/* do include loopback interfaces */
86    LOOP_IF_NONE    = 2,	/* include loopback if no other if's */
87    EXTRA_ADDRESSES = 4,	/* include extra addresses */
88    SCAN_INTERFACES = 8		/* scan interfaces for addresses */
89};
90
91/*
92 * Try to figure out the addresses of all configured interfaces with a
93 * lot of magic ioctls.
94 */
95
96static krb5_error_code
97find_all_addresses (krb5_context context, krb5_addresses *res, int flags)
98{
99    struct sockaddr sa_zero;
100    struct ifaddrs *ifa0, *ifa;
101    krb5_error_code ret = ENXIO;
102    unsigned int num, idx;
103    krb5_addresses ignore_addresses;
104
105    if (getifaddrs(&ifa0) == -1) {
106	ret = errno;
107	krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret));
108	return (ret);
109    }
110
111    memset(&sa_zero, 0, sizeof(sa_zero));
112
113    /* First, count all the ifaddrs. */
114    for (ifa = ifa0, num = 0; ifa != NULL; ifa = ifa->ifa_next, num++)
115	/* nothing */;
116
117    if (num == 0) {
118	freeifaddrs(ifa0);
119	krb5_set_error_message(context, ENXIO, N_("no addresses found", ""));
120	return (ENXIO);
121    }
122
123    if (flags & EXTRA_ADDRESSES) {
124	/* we'll remove the addresses we don't care about */
125	ret = krb5_get_ignore_addresses(context, &ignore_addresses);
126	if(ret)
127	    return ret;
128    }
129
130    /* Allocate storage for them. */
131    res->val = calloc(num, sizeof(*res->val));
132    if (res->val == NULL) {
133	krb5_free_addresses(context, &ignore_addresses);
134	freeifaddrs(ifa0);
135	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
136	return ENOMEM;
137    }
138
139    /* Now traverse the list. */
140    for (ifa = ifa0, idx = 0; ifa != NULL; ifa = ifa->ifa_next) {
141	if ((ifa->ifa_flags & IFF_UP) == 0)
142	    continue;
143	if (ifa->ifa_addr == NULL)
144	    continue;
145	if (memcmp(ifa->ifa_addr, &sa_zero, sizeof(sa_zero)) == 0)
146	    continue;
147	if (krb5_sockaddr_uninteresting(ifa->ifa_addr))
148	    continue;
149	if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
150	    /* We'll deal with the LOOP_IF_NONE case later. */
151	    if ((flags & LOOP) == 0)
152		continue;
153	}
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
193	    if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) {
194		ret = krb5_sockaddr2address(context,
195					    ifa->ifa_addr, &res->val[idx]);
196		if (ret) {
197		    /*
198		     * See comment above.
199		     */
200		    continue;
201		}
202		if((flags & EXTRA_ADDRESSES) &&
203		   krb5_address_search(context, &res->val[idx],
204				       &ignore_addresses)) {
205		    krb5_free_address(context, &res->val[idx]);
206		    continue;
207		}
208		idx++;
209	    }
210	}
211    }
212
213    if (flags & EXTRA_ADDRESSES)
214	krb5_free_addresses(context, &ignore_addresses);
215    freeifaddrs(ifa0);
216    if (ret) {
217	free(res->val);
218	res->val = NULL;
219    } else
220	res->len = idx;        /* Now a count. */
221    return (ret);
222}
223
224static krb5_error_code
225get_addrs_int (krb5_context context, krb5_addresses *res, int flags)
226{
227    krb5_error_code ret = -1;
228
229    res->len = 0;
230    res->val = NULL;
231
232    if (flags & SCAN_INTERFACES) {
233	ret = find_all_addresses (context, res, flags);
234	if(ret || res->len == 0)
235	    ret = gethostname_fallback (context, res);
236    } else {
237	ret = 0;
238    }
239
240    if(ret == 0 && (flags & EXTRA_ADDRESSES)) {
241	krb5_addresses a;
242	/* append user specified addresses */
243	ret = krb5_get_extra_addresses(context, &a);
244	if(ret) {
245	    krb5_free_addresses(context, res);
246	    return ret;
247	}
248	ret = krb5_append_addresses(context, res, &a);
249	if(ret) {
250	    krb5_free_addresses(context, res);
251	    return ret;
252	}
253	krb5_free_addresses(context, &a);
254    }
255    if(res->len == 0) {
256	free(res->val);
257	res->val = NULL;
258    }
259    return ret;
260}
261
262/*
263 * Try to get all addresses, but return the one corresponding to
264 * `hostname' if we fail.
265 *
266 * Only include loopback address if there are no other.
267 */
268
269krb5_error_code KRB5_LIB_FUNCTION
270krb5_get_all_client_addrs (krb5_context context, krb5_addresses *res)
271{
272    int flags = LOOP_IF_NONE | EXTRA_ADDRESSES;
273
274    if (context->scan_interfaces)
275	flags |= SCAN_INTERFACES;
276
277    return get_addrs_int (context, res, flags);
278}
279
280/*
281 * Try to get all local addresses that a server should listen to.
282 * If that fails, we return the address corresponding to `hostname'.
283 */
284
285krb5_error_code KRB5_LIB_FUNCTION
286krb5_get_all_server_addrs (krb5_context context, krb5_addresses *res)
287{
288    return get_addrs_int (context, res, LOOP | SCAN_INTERFACES);
289}
290