155682Smarkm/* 2178825Sdfr * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm#include <resolve.h> 3655682Smarkm 37178825SdfrRCSID("$Id: get_host_realm.c 18541 2006-10-17 19:28:36Z lha $"); 3855682Smarkm 3955682Smarkm/* To automagically find the correct realm of a host (without 4055682Smarkm * [domain_realm] in krb5.conf) add a text record for your domain with 4155682Smarkm * the name of your realm, like this: 4255682Smarkm * 43102644Snectar * _kerberos IN TXT "FOO.SE" 4455682Smarkm * 4555682Smarkm * The search is recursive, so you can add entries for specific 4655682Smarkm * hosts. To find the realm of host a.b.c, it first tries 47102644Snectar * _kerberos.a.b.c, then _kerberos.b.c and so on. 4855682Smarkm * 49102644Snectar * This method is described in draft-ietf-cat-krb-dns-locate-03.txt. 5055682Smarkm * 5155682Smarkm */ 5255682Smarkm 5355682Smarkmstatic int 5455682Smarkmcopy_txt_to_realms (struct resource_record *head, 5555682Smarkm krb5_realm **realms) 5655682Smarkm{ 5755682Smarkm struct resource_record *rr; 5855682Smarkm int n, i; 5955682Smarkm 6055682Smarkm for(n = 0, rr = head; rr; rr = rr->next) 6155682Smarkm if (rr->type == T_TXT) 6255682Smarkm ++n; 6355682Smarkm 6455682Smarkm if (n == 0) 6555682Smarkm return -1; 6655682Smarkm 6755682Smarkm *realms = malloc ((n + 1) * sizeof(krb5_realm)); 6855682Smarkm if (*realms == NULL) 6955682Smarkm return -1; 7055682Smarkm 7155682Smarkm for (i = 0; i < n + 1; ++i) 7255682Smarkm (*realms)[i] = NULL; 7355682Smarkm 7455682Smarkm for (i = 0, rr = head; rr; rr = rr->next) { 7555682Smarkm if (rr->type == T_TXT) { 7655682Smarkm char *tmp; 7755682Smarkm 7855682Smarkm tmp = strdup(rr->u.txt); 7955682Smarkm if (tmp == NULL) { 8055682Smarkm for (i = 0; i < n; ++i) 8155682Smarkm free ((*realms)[i]); 8255682Smarkm free (*realms); 8355682Smarkm return -1; 8455682Smarkm } 8555682Smarkm (*realms)[i] = tmp; 8655682Smarkm ++i; 8755682Smarkm } 8855682Smarkm } 8955682Smarkm return 0; 9055682Smarkm} 9155682Smarkm 9255682Smarkmstatic int 9355682Smarkmdns_find_realm(krb5_context context, 9455682Smarkm const char *domain, 9555682Smarkm krb5_realm **realms) 9655682Smarkm{ 97178825Sdfr static const char *default_labels[] = { "_kerberos", NULL }; 9855682Smarkm char dom[MAXHOSTNAMELEN]; 9955682Smarkm struct dns_reply *r; 100178825Sdfr const char **labels; 101178825Sdfr char **config_labels; 102102644Snectar int i, ret; 10355682Smarkm 104178825Sdfr config_labels = krb5_config_get_strings(context, NULL, "libdefaults", 105178825Sdfr "dns_lookup_realm_labels", NULL); 106178825Sdfr if(config_labels != NULL) 107178825Sdfr labels = (const char **)config_labels; 108178825Sdfr else 109102644Snectar labels = default_labels; 11055682Smarkm if(*domain == '.') 11155682Smarkm domain++; 112102644Snectar for (i = 0; labels[i] != NULL; i++) { 113178825Sdfr ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); 114178825Sdfr if(ret < 0 || ret >= sizeof(dom)) { 115178825Sdfr if (config_labels) 116178825Sdfr krb5_config_free_strings(config_labels); 117102644Snectar return -1; 118178825Sdfr } 119102644Snectar r = dns_lookup(dom, "TXT"); 120102644Snectar if(r != NULL) { 121102644Snectar ret = copy_txt_to_realms (r->head, realms); 122102644Snectar dns_free_data(r); 123178825Sdfr if(ret == 0) { 124178825Sdfr if (config_labels) 125178825Sdfr krb5_config_free_strings(config_labels); 126102644Snectar return 0; 127178825Sdfr } 128102644Snectar } 129102644Snectar } 130178825Sdfr if (config_labels) 131178825Sdfr krb5_config_free_strings(config_labels); 132102644Snectar return -1; 13355682Smarkm} 13455682Smarkm 13555682Smarkm/* 13655682Smarkm * Try to figure out what realms host in `domain' belong to from the 13755682Smarkm * configuration file. 13855682Smarkm */ 13955682Smarkm 14055682Smarkmstatic int 14155682Smarkmconfig_find_realm(krb5_context context, 14255682Smarkm const char *domain, 14355682Smarkm krb5_realm **realms) 14455682Smarkm{ 14555682Smarkm char **tmp = krb5_config_get_strings (context, NULL, 14655682Smarkm "domain_realm", 14755682Smarkm domain, 14855682Smarkm NULL); 14955682Smarkm 15055682Smarkm if (tmp == NULL) 15155682Smarkm return -1; 15255682Smarkm *realms = tmp; 15355682Smarkm return 0; 15455682Smarkm} 15555682Smarkm 15655682Smarkm/* 15755682Smarkm * This function assumes that `host' is a FQDN (and doesn't handle the 15855682Smarkm * special case of host == NULL either). 15955682Smarkm * Try to find mapping in the config file or DNS and it that fails, 16055682Smarkm * fall back to guessing 16155682Smarkm */ 16255682Smarkm 163178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 164178825Sdfr_krb5_get_host_realm_int (krb5_context context, 165178825Sdfr const char *host, 166178825Sdfr krb5_boolean use_dns, 167178825Sdfr krb5_realm **realms) 16855682Smarkm{ 169102644Snectar const char *p, *q; 170102644Snectar krb5_boolean dns_locate_enable; 17155682Smarkm 172102644Snectar dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, 173102644Snectar "libdefaults", "dns_lookup_realm", NULL); 17455682Smarkm for (p = host; p != NULL; p = strchr (p + 1, '.')) { 175102644Snectar if(config_find_realm(context, p, realms) == 0) { 176102644Snectar if(strcasecmp(*realms[0], "dns_locate") == 0) { 177102644Snectar if(use_dns) 178102644Snectar for (q = host; q != NULL; q = strchr(q + 1, '.')) 179102644Snectar if(dns_find_realm(context, q, realms) == 0) 180102644Snectar return 0; 181102644Snectar continue; 182102644Snectar } else 183102644Snectar return 0; 184102644Snectar } 185102644Snectar else if(use_dns && dns_locate_enable) { 186102644Snectar if(dns_find_realm(context, p, realms) == 0) 18778527Sassar return 0; 18878527Sassar } 18955682Smarkm } 19055682Smarkm p = strchr(host, '.'); 19155682Smarkm if(p != NULL) { 19255682Smarkm p++; 19355682Smarkm *realms = malloc(2 * sizeof(krb5_realm)); 19478527Sassar if (*realms == NULL) { 19578527Sassar krb5_set_error_string(context, "malloc: out of memory"); 19655682Smarkm return ENOMEM; 19778527Sassar } 19855682Smarkm 19955682Smarkm (*realms)[0] = strdup(p); 20055682Smarkm if((*realms)[0] == NULL) { 20155682Smarkm free(*realms); 20278527Sassar krb5_set_error_string(context, "malloc: out of memory"); 20355682Smarkm return ENOMEM; 20455682Smarkm } 20555682Smarkm strupr((*realms)[0]); 20655682Smarkm (*realms)[1] = NULL; 20755682Smarkm return 0; 20855682Smarkm } 20978527Sassar krb5_set_error_string(context, "unable to find realm of host %s", host); 21055682Smarkm return KRB5_ERR_HOST_REALM_UNKNOWN; 21155682Smarkm} 21255682Smarkm 21355682Smarkm/* 214178825Sdfr * Return the realm(s) of `host' as a NULL-terminated list in 215178825Sdfr * `realms'. Free `realms' with krb5_free_host_realm(). 21655682Smarkm */ 21755682Smarkm 218178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION 21955682Smarkmkrb5_get_host_realm(krb5_context context, 220178825Sdfr const char *targethost, 22155682Smarkm krb5_realm **realms) 22255682Smarkm{ 223178825Sdfr const char *host = targethost; 22455682Smarkm char hostname[MAXHOSTNAMELEN]; 225178825Sdfr krb5_error_code ret; 226178825Sdfr int use_dns; 22755682Smarkm 22855682Smarkm if (host == NULL) { 229178825Sdfr if (gethostname (hostname, sizeof(hostname))) { 230178825Sdfr *realms = NULL; 23155682Smarkm return errno; 232178825Sdfr } 23355682Smarkm host = hostname; 23455682Smarkm } 23555682Smarkm 236178825Sdfr /* 237178825Sdfr * If our local hostname is without components, don't even try to dns. 238178825Sdfr */ 239178825Sdfr 240178825Sdfr use_dns = (strchr(host, '.') != NULL); 241178825Sdfr 242178825Sdfr ret = _krb5_get_host_realm_int (context, host, use_dns, realms); 243178825Sdfr if (ret && targethost != NULL) { 244178825Sdfr /* 245178825Sdfr * If there was no realm mapping for the host (and we wasn't 246178825Sdfr * looking for ourself), guess at the local realm, maybe our 247178825Sdfr * KDC knows better then we do and we get a referral back. 248178825Sdfr */ 249178825Sdfr ret = krb5_get_default_realms(context, realms); 250178825Sdfr if (ret) { 251178825Sdfr krb5_set_error_string(context, "Unable to find realm of host %s", 252178825Sdfr host); 253178825Sdfr return KRB5_ERR_HOST_REALM_UNKNOWN; 254178825Sdfr } 255178825Sdfr } 256178825Sdfr return ret; 25755682Smarkm} 258