1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3b528cefcSMark Murray * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray * All rights reserved.
5b528cefcSMark Murray *
6b528cefcSMark Murray * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray * modification, are permitted provided that the following conditions
8b528cefcSMark Murray * are met:
9b528cefcSMark Murray *
10b528cefcSMark Murray * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray * notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray *
13b528cefcSMark Murray * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray * notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray * documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray *
17b528cefcSMark Murray * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray * may be used to endorse or promote products derived from this software
19b528cefcSMark Murray * without specific prior written permission.
20b528cefcSMark Murray *
21b528cefcSMark Murray * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray * SUCH DAMAGE.
32b528cefcSMark Murray */
33b528cefcSMark Murray
34b528cefcSMark Murray #include "krb5_locl.h"
35b528cefcSMark Murray #include <resolve.h>
36b528cefcSMark Murray
37b528cefcSMark Murray /* To automagically find the correct realm of a host (without
38b528cefcSMark Murray * [domain_realm] in krb5.conf) add a text record for your domain with
39b528cefcSMark Murray * the name of your realm, like this:
40b528cefcSMark Murray *
418373020dSJacques Vidrine * _kerberos IN TXT "FOO.SE"
42b528cefcSMark Murray *
43b528cefcSMark Murray * The search is recursive, so you can add entries for specific
44b528cefcSMark Murray * hosts. To find the realm of host a.b.c, it first tries
458373020dSJacques Vidrine * _kerberos.a.b.c, then _kerberos.b.c and so on.
46b528cefcSMark Murray *
478373020dSJacques Vidrine * This method is described in draft-ietf-cat-krb-dns-locate-03.txt.
48b528cefcSMark Murray *
49b528cefcSMark Murray */
50b528cefcSMark Murray
51b528cefcSMark Murray static int
copy_txt_to_realms(struct rk_resource_record * head,krb5_realm ** realms)52*ae771770SStanislav Sedov copy_txt_to_realms (struct rk_resource_record *head,
53b528cefcSMark Murray krb5_realm **realms)
54b528cefcSMark Murray {
55*ae771770SStanislav Sedov struct rk_resource_record *rr;
56*ae771770SStanislav Sedov unsigned int n, i;
57b528cefcSMark Murray
58b528cefcSMark Murray for(n = 0, rr = head; rr; rr = rr->next)
59*ae771770SStanislav Sedov if (rr->type == rk_ns_t_txt)
60b528cefcSMark Murray ++n;
61b528cefcSMark Murray
62b528cefcSMark Murray if (n == 0)
63b528cefcSMark Murray return -1;
64b528cefcSMark Murray
65b528cefcSMark Murray *realms = malloc ((n + 1) * sizeof(krb5_realm));
66b528cefcSMark Murray if (*realms == NULL)
67b528cefcSMark Murray return -1;
68b528cefcSMark Murray
69b528cefcSMark Murray for (i = 0; i < n + 1; ++i)
70b528cefcSMark Murray (*realms)[i] = NULL;
71b528cefcSMark Murray
72b528cefcSMark Murray for (i = 0, rr = head; rr; rr = rr->next) {
73*ae771770SStanislav Sedov if (rr->type == rk_ns_t_txt) {
74b528cefcSMark Murray char *tmp;
75b528cefcSMark Murray
76b528cefcSMark Murray tmp = strdup(rr->u.txt);
77b528cefcSMark Murray if (tmp == NULL) {
78b528cefcSMark Murray for (i = 0; i < n; ++i)
79b528cefcSMark Murray free ((*realms)[i]);
80b528cefcSMark Murray free (*realms);
81b528cefcSMark Murray return -1;
82b528cefcSMark Murray }
83b528cefcSMark Murray (*realms)[i] = tmp;
84b528cefcSMark Murray ++i;
85b528cefcSMark Murray }
86b528cefcSMark Murray }
87b528cefcSMark Murray return 0;
88b528cefcSMark Murray }
89b528cefcSMark Murray
90b528cefcSMark Murray static int
dns_find_realm(krb5_context context,const char * domain,krb5_realm ** realms)91b528cefcSMark Murray dns_find_realm(krb5_context context,
92b528cefcSMark Murray const char *domain,
93b528cefcSMark Murray krb5_realm **realms)
94b528cefcSMark Murray {
95c19800e8SDoug Rabson static const char *default_labels[] = { "_kerberos", NULL };
96b528cefcSMark Murray char dom[MAXHOSTNAMELEN];
97*ae771770SStanislav Sedov struct rk_dns_reply *r;
98c19800e8SDoug Rabson const char **labels;
99c19800e8SDoug Rabson char **config_labels;
1008373020dSJacques Vidrine int i, ret;
101b528cefcSMark Murray
102c19800e8SDoug Rabson config_labels = krb5_config_get_strings(context, NULL, "libdefaults",
1038373020dSJacques Vidrine "dns_lookup_realm_labels", NULL);
104c19800e8SDoug Rabson if(config_labels != NULL)
105c19800e8SDoug Rabson labels = (const char **)config_labels;
106c19800e8SDoug Rabson else
1078373020dSJacques Vidrine labels = default_labels;
108b528cefcSMark Murray if(*domain == '.')
109b528cefcSMark Murray domain++;
1108373020dSJacques Vidrine for (i = 0; labels[i] != NULL; i++) {
111c19800e8SDoug Rabson ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain);
112*ae771770SStanislav Sedov if(ret < 0 || (size_t)ret >= sizeof(dom)) {
113c19800e8SDoug Rabson if (config_labels)
114c19800e8SDoug Rabson krb5_config_free_strings(config_labels);
115b528cefcSMark Murray return -1;
116c19800e8SDoug Rabson }
117*ae771770SStanislav Sedov r = rk_dns_lookup(dom, "TXT");
1188373020dSJacques Vidrine if(r != NULL) {
119b528cefcSMark Murray ret = copy_txt_to_realms (r->head, realms);
120*ae771770SStanislav Sedov rk_dns_free_data(r);
121c19800e8SDoug Rabson if(ret == 0) {
122c19800e8SDoug Rabson if (config_labels)
123c19800e8SDoug Rabson krb5_config_free_strings(config_labels);
1248373020dSJacques Vidrine return 0;
1258373020dSJacques Vidrine }
1268373020dSJacques Vidrine }
127c19800e8SDoug Rabson }
128c19800e8SDoug Rabson if (config_labels)
129c19800e8SDoug Rabson krb5_config_free_strings(config_labels);
1308373020dSJacques Vidrine return -1;
131b528cefcSMark Murray }
132b528cefcSMark Murray
133b528cefcSMark Murray /*
134b528cefcSMark Murray * Try to figure out what realms host in `domain' belong to from the
135b528cefcSMark Murray * configuration file.
136b528cefcSMark Murray */
137b528cefcSMark Murray
138b528cefcSMark Murray static int
config_find_realm(krb5_context context,const char * domain,krb5_realm ** realms)139b528cefcSMark Murray config_find_realm(krb5_context context,
140b528cefcSMark Murray const char *domain,
141b528cefcSMark Murray krb5_realm **realms)
142b528cefcSMark Murray {
143b528cefcSMark Murray char **tmp = krb5_config_get_strings (context, NULL,
144b528cefcSMark Murray "domain_realm",
145b528cefcSMark Murray domain,
146b528cefcSMark Murray NULL);
147b528cefcSMark Murray
148b528cefcSMark Murray if (tmp == NULL)
149b528cefcSMark Murray return -1;
150b528cefcSMark Murray *realms = tmp;
151b528cefcSMark Murray return 0;
152b528cefcSMark Murray }
153b528cefcSMark Murray
154b528cefcSMark Murray /*
155b528cefcSMark Murray * This function assumes that `host' is a FQDN (and doesn't handle the
156b528cefcSMark Murray * special case of host == NULL either).
157b528cefcSMark Murray * Try to find mapping in the config file or DNS and it that fails,
158b528cefcSMark Murray * fall back to guessing
159b528cefcSMark Murray */
160b528cefcSMark Murray
161*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_get_host_realm_int(krb5_context context,const char * host,krb5_boolean use_dns,krb5_realm ** realms)162c19800e8SDoug Rabson _krb5_get_host_realm_int (krb5_context context,
163b528cefcSMark Murray const char *host,
164adb0ddaeSAssar Westerlund krb5_boolean use_dns,
165b528cefcSMark Murray krb5_realm **realms)
166b528cefcSMark Murray {
1678373020dSJacques Vidrine const char *p, *q;
1688373020dSJacques Vidrine krb5_boolean dns_locate_enable;
169b528cefcSMark Murray
1708373020dSJacques Vidrine dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE,
1718373020dSJacques Vidrine "libdefaults", "dns_lookup_realm", NULL);
172b528cefcSMark Murray for (p = host; p != NULL; p = strchr (p + 1, '.')) {
1738373020dSJacques Vidrine if(config_find_realm(context, p, realms) == 0) {
1748373020dSJacques Vidrine if(strcasecmp(*realms[0], "dns_locate") == 0) {
1758373020dSJacques Vidrine if(use_dns)
1768373020dSJacques Vidrine for (q = host; q != NULL; q = strchr(q + 1, '.'))
1778373020dSJacques Vidrine if(dns_find_realm(context, q, realms) == 0)
178b528cefcSMark Murray return 0;
1798373020dSJacques Vidrine continue;
1808373020dSJacques Vidrine } else
181b528cefcSMark Murray return 0;
1828373020dSJacques Vidrine }
1838373020dSJacques Vidrine else if(use_dns && dns_locate_enable) {
1848373020dSJacques Vidrine if(dns_find_realm(context, p, realms) == 0)
185b528cefcSMark Murray return 0;
186b528cefcSMark Murray }
187adb0ddaeSAssar Westerlund }
188b528cefcSMark Murray p = strchr(host, '.');
189b528cefcSMark Murray if(p != NULL) {
190b528cefcSMark Murray p++;
191b528cefcSMark Murray *realms = malloc(2 * sizeof(krb5_realm));
192adb0ddaeSAssar Westerlund if (*realms == NULL) {
193*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
194b528cefcSMark Murray return ENOMEM;
195adb0ddaeSAssar Westerlund }
196b528cefcSMark Murray
197b528cefcSMark Murray (*realms)[0] = strdup(p);
198b528cefcSMark Murray if((*realms)[0] == NULL) {
199b528cefcSMark Murray free(*realms);
200*ae771770SStanislav Sedov krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
201b528cefcSMark Murray return ENOMEM;
202b528cefcSMark Murray }
203b528cefcSMark Murray strupr((*realms)[0]);
204b528cefcSMark Murray (*realms)[1] = NULL;
205b528cefcSMark Murray return 0;
206b528cefcSMark Murray }
207*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
208*ae771770SStanislav Sedov N_("unable to find realm of host %s", ""),
209*ae771770SStanislav Sedov host);
210b528cefcSMark Murray return KRB5_ERR_HOST_REALM_UNKNOWN;
211b528cefcSMark Murray }
212b528cefcSMark Murray
213b528cefcSMark Murray /*
214c19800e8SDoug Rabson * Return the realm(s) of `host' as a NULL-terminated list in
215c19800e8SDoug Rabson * `realms'. Free `realms' with krb5_free_host_realm().
216b528cefcSMark Murray */
217b528cefcSMark Murray
218*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_get_host_realm(krb5_context context,const char * targethost,krb5_realm ** realms)219b528cefcSMark Murray krb5_get_host_realm(krb5_context context,
220c19800e8SDoug Rabson const char *targethost,
221b528cefcSMark Murray krb5_realm **realms)
222b528cefcSMark Murray {
223c19800e8SDoug Rabson const char *host = targethost;
224b528cefcSMark Murray char hostname[MAXHOSTNAMELEN];
225c19800e8SDoug Rabson krb5_error_code ret;
226c19800e8SDoug Rabson int use_dns;
227b528cefcSMark Murray
228b528cefcSMark Murray if (host == NULL) {
229c19800e8SDoug Rabson if (gethostname (hostname, sizeof(hostname))) {
230c19800e8SDoug Rabson *realms = NULL;
231b528cefcSMark Murray return errno;
232c19800e8SDoug Rabson }
233b528cefcSMark Murray host = hostname;
234b528cefcSMark Murray }
235b528cefcSMark Murray
236c19800e8SDoug Rabson /*
237c19800e8SDoug Rabson * If our local hostname is without components, don't even try to dns.
238c19800e8SDoug Rabson */
239c19800e8SDoug Rabson
240c19800e8SDoug Rabson use_dns = (strchr(host, '.') != NULL);
241c19800e8SDoug Rabson
242c19800e8SDoug Rabson ret = _krb5_get_host_realm_int (context, host, use_dns, realms);
243c19800e8SDoug Rabson if (ret && targethost != NULL) {
244c19800e8SDoug Rabson /*
245c19800e8SDoug Rabson * If there was no realm mapping for the host (and we wasn't
246c19800e8SDoug Rabson * looking for ourself), guess at the local realm, maybe our
247c19800e8SDoug Rabson * KDC knows better then we do and we get a referral back.
248c19800e8SDoug Rabson */
249c19800e8SDoug Rabson ret = krb5_get_default_realms(context, realms);
250c19800e8SDoug Rabson if (ret) {
251*ae771770SStanislav Sedov krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN,
252*ae771770SStanislav Sedov N_("Unable to find realm of host %s", ""),
253c19800e8SDoug Rabson host);
254c19800e8SDoug Rabson return KRB5_ERR_HOST_REALM_UNKNOWN;
255c19800e8SDoug Rabson }
256c19800e8SDoug Rabson }
257c19800e8SDoug Rabson return ret;
258b528cefcSMark Murray }
259