~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/get_addrs.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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)
 
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)
 
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)
 
292
{
 
293
    return get_addrs_int (context, res, LOOP | SCAN_INTERFACES);
 
294
}