~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/get_host_realm.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 - 2005 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
#include <resolve.h>
 
36
 
 
37
RCSID("$Id$");
 
38
 
 
39
/* To automagically find the correct realm of a host (without
 
40
 * [domain_realm] in krb5.conf) add a text record for your domain with
 
41
 * the name of your realm, like this:
 
42
 *
 
43
 * _kerberos    IN      TXT     "FOO.SE"
 
44
 *
 
45
 * The search is recursive, so you can add entries for specific
 
46
 * hosts. To find the realm of host a.b.c, it first tries
 
47
 * _kerberos.a.b.c, then _kerberos.b.c and so on.
 
48
 *
 
49
 * This method is described in draft-ietf-cat-krb-dns-locate-03.txt.
 
50
 *
 
51
 */
 
52
 
 
53
static int
 
54
copy_txt_to_realms (struct resource_record *head,
 
55
                    krb5_realm **realms)
 
56
{
 
57
    struct resource_record *rr;
 
58
    unsigned int n, i;
 
59
 
 
60
    for(n = 0, rr = head; rr; rr = rr->next)
 
61
        if (rr->type == T_TXT)
 
62
            ++n;
 
63
 
 
64
    if (n == 0)
 
65
        return -1;
 
66
 
 
67
    *realms = malloc ((n + 1) * sizeof(krb5_realm));
 
68
    if (*realms == NULL)
 
69
        return -1;
 
70
 
 
71
    for (i = 0; i < n + 1; ++i)
 
72
        (*realms)[i] = NULL;
 
73
 
 
74
    for (i = 0, rr = head; rr; rr = rr->next) {
 
75
        if (rr->type == T_TXT) {
 
76
            char *tmp;
 
77
 
 
78
            tmp = strdup(rr->u.txt);
 
79
            if (tmp == NULL) {
 
80
                for (i = 0; i < n; ++i)
 
81
                    free ((*realms)[i]);
 
82
                free (*realms);
 
83
                return -1;
 
84
            }
 
85
            (*realms)[i] = tmp;
 
86
            ++i;
 
87
        }
 
88
    }
 
89
    return 0;
 
90
}
 
91
 
 
92
static int
 
93
dns_find_realm(krb5_context context,
 
94
               const char *domain,
 
95
               krb5_realm **realms)
 
96
{
 
97
    static const char *default_labels[] = { "_kerberos", NULL };
 
98
    char dom[MAXHOSTNAMELEN];
 
99
    struct dns_reply *r;
 
100
    const char **labels;
 
101
    char **config_labels;
 
102
    int i, ret;
 
103
 
 
104
    config_labels = krb5_config_get_strings(context, NULL, "libdefaults",
 
105
                                            "dns_lookup_realm_labels", NULL);
 
106
    if(config_labels != NULL)
 
107
        labels = (const char **)config_labels;
 
108
    else
 
109
        labels = default_labels;
 
110
    if(*domain == '.')
 
111
        domain++;
 
112
    for (i = 0; labels[i] != NULL; i++) {
 
113
        ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain);
 
114
        if(ret < 0 || ret >= sizeof(dom)) {
 
115
            if (config_labels)
 
116
                krb5_config_free_strings(config_labels);
 
117
            return -1;
 
118
        }
 
119
        r = dns_lookup(dom, "TXT");
 
120
        if(r != NULL) {
 
121
            ret = copy_txt_to_realms (r->head, realms);
 
122
            dns_free_data(r);
 
123
            if(ret == 0) {
 
124
                if (config_labels)
 
125
                    krb5_config_free_strings(config_labels);
 
126
                return 0;
 
127
            }
 
128
        }
 
129
    }
 
130
    if (config_labels)
 
131
        krb5_config_free_strings(config_labels);
 
132
    return -1;
 
133
}
 
134
 
 
135
/*
 
136
 * Try to figure out what realms host in `domain' belong to from the
 
137
 * configuration file.
 
138
 */
 
139
 
 
140
static int
 
141
config_find_realm(krb5_context context,
 
142
                  const char *domain,
 
143
                  krb5_realm **realms)
 
144
{
 
145
    char **tmp = krb5_config_get_strings (context, NULL,
 
146
                                          "domain_realm",
 
147
                                          domain,
 
148
                                          NULL);
 
149
 
 
150
    if (tmp == NULL)
 
151
        return -1;
 
152
    *realms = tmp;
 
153
    return 0;
 
154
}
 
155
 
 
156
/*
 
157
 * This function assumes that `host' is a FQDN (and doesn't handle the
 
158
 * special case of host == NULL either).
 
159
 * Try to find mapping in the config file or DNS and it that fails,
 
160
 * fall back to guessing
 
161
 */
 
162
 
 
163
krb5_error_code KRB5_LIB_FUNCTION
 
164
_krb5_get_host_realm_int (krb5_context context,
 
165
                          const char *host,
 
166
                          krb5_boolean use_dns,
 
167
                          krb5_realm **realms)
 
168
{
 
169
    const char *p, *q;
 
170
    krb5_boolean dns_locate_enable;
 
171
 
 
172
    dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE,
 
173
        "libdefaults", "dns_lookup_realm", NULL);
 
174
    for (p = host; p != NULL; p = strchr (p + 1, '.')) {
 
175
        if(config_find_realm(context, p, realms) == 0) {
 
176
            if(strcasecmp(*realms[0], "dns_locate") == 0) {
 
177
                if(use_dns)
 
178
                    for (q = host; q != NULL; q = strchr(q + 1, '.'))
 
179
                        if(dns_find_realm(context, q, realms) == 0)
 
180
                            return 0;
 
181
                continue;
 
182
            } else
 
183
                return 0;
 
184
        }
 
185
        else if(use_dns && dns_locate_enable) {
 
186
            if(dns_find_realm(context, p, realms) == 0)
 
187
                return 0;
 
188
        }
 
189
    }
 
190
    p = strchr(host, '.');
 
191
    if(p != NULL) {
 
192
        p++;
 
193
        *realms = malloc(2 * sizeof(krb5_realm));
 
194
        if (*realms == NULL) {
 
195
            krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 
196
            return ENOMEM;
 
197
        }
 
198
 
 
199
        (*realms)[0] = strdup(p);
 
200
        if((*realms)[0] == NULL) {
 
201
            free(*realms);
 
202
            krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
 
203
            return ENOMEM;
 
204
        }
 
205
        strupr((*realms)[0]);
 
206
        (*realms)[1] = NULL;
 
207
        return 0;
 
208
    }
 
209
    krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
 
210
                           N_("unable to find realm of host %s", ""),
 
211
                           host);
 
212
    return KRB5_ERR_HOST_REALM_UNKNOWN;
 
213
}
 
214
 
 
215
/*
 
216
 * Return the realm(s) of `host' as a NULL-terminated list in
 
217
 * `realms'. Free `realms' with krb5_free_host_realm().
 
218
 */
 
219
 
 
220
krb5_error_code KRB5_LIB_FUNCTION
 
221
krb5_get_host_realm(krb5_context context,
 
222
                    const char *targethost,
 
223
                    krb5_realm **realms)
 
224
{
 
225
    const char *host = targethost;
 
226
    char hostname[MAXHOSTNAMELEN];
 
227
    krb5_error_code ret;
 
228
    int use_dns;
 
229
 
 
230
    if (host == NULL) {
 
231
        if (gethostname (hostname, sizeof(hostname))) {
 
232
            *realms = NULL;
 
233
            return errno;
 
234
        }
 
235
        host = hostname;
 
236
    }
 
237
 
 
238
    /*
 
239
     * If our local hostname is without components, don't even try to dns.
 
240
     */
 
241
 
 
242
    use_dns = (strchr(host, '.') != NULL);
 
243
 
 
244
    ret = _krb5_get_host_realm_int (context, host, use_dns, realms);
 
245
    if (ret && targethost != NULL) {
 
246
        /*
 
247
         * If there was no realm mapping for the host (and we wasn't
 
248
         * looking for ourself), guess at the local realm, maybe our
 
249
         * KDC knows better then we do and we get a referral back.
 
250
         */
 
251
        ret = krb5_get_default_realms(context, realms);
 
252
        if (ret) {
 
253
            krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
 
254
                                   N_("Unable to find realm of host %s", ""),
 
255
                                   host);
 
256
            return KRB5_ERR_HOST_REALM_UNKNOWN;
 
257
        }
 
258
    }
 
259
    return ret;
 
260
}