155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "krb5_locl.h" 3555682Smarkm#include <resolve.h> 3655682Smarkm 3755682Smarkm/* To automagically find the correct realm of a host (without 3855682Smarkm * [domain_realm] in krb5.conf) add a text record for your domain with 3955682Smarkm * the name of your realm, like this: 4055682Smarkm * 41102644Snectar * _kerberos IN TXT "FOO.SE" 4255682Smarkm * 4355682Smarkm * The search is recursive, so you can add entries for specific 4455682Smarkm * hosts. To find the realm of host a.b.c, it first tries 45102644Snectar * _kerberos.a.b.c, then _kerberos.b.c and so on. 4655682Smarkm * 47102644Snectar * This method is described in draft-ietf-cat-krb-dns-locate-03.txt. 4855682Smarkm * 4955682Smarkm */ 5055682Smarkm 5155682Smarkmstatic int 52233294Sstascopy_txt_to_realms (struct rk_resource_record *head, 5355682Smarkm krb5_realm **realms) 5455682Smarkm{ 55233294Sstas struct rk_resource_record *rr; 56233294Sstas unsigned int n, i; 5755682Smarkm 5855682Smarkm for(n = 0, rr = head; rr; rr = rr->next) 59233294Sstas if (rr->type == rk_ns_t_txt) 6055682Smarkm ++n; 6155682Smarkm 6255682Smarkm if (n == 0) 6355682Smarkm return -1; 6455682Smarkm 6555682Smarkm *realms = malloc ((n + 1) * sizeof(krb5_realm)); 6655682Smarkm if (*realms == NULL) 6755682Smarkm return -1; 6855682Smarkm 6955682Smarkm for (i = 0; i < n + 1; ++i) 7055682Smarkm (*realms)[i] = NULL; 7155682Smarkm 7255682Smarkm for (i = 0, rr = head; rr; rr = rr->next) { 73233294Sstas if (rr->type == rk_ns_t_txt) { 7455682Smarkm char *tmp; 7555682Smarkm 7655682Smarkm tmp = strdup(rr->u.txt); 7755682Smarkm if (tmp == NULL) { 7855682Smarkm for (i = 0; i < n; ++i) 7955682Smarkm free ((*realms)[i]); 8055682Smarkm free (*realms); 8155682Smarkm return -1; 8255682Smarkm } 8355682Smarkm (*realms)[i] = tmp; 8455682Smarkm ++i; 8555682Smarkm } 8655682Smarkm } 8755682Smarkm return 0; 8855682Smarkm} 8955682Smarkm 9055682Smarkmstatic int 9155682Smarkmdns_find_realm(krb5_context context, 9255682Smarkm const char *domain, 9355682Smarkm krb5_realm **realms) 9455682Smarkm{ 95178825Sdfr static const char *default_labels[] = { "_kerberos", NULL }; 9655682Smarkm char dom[MAXHOSTNAMELEN]; 97233294Sstas struct rk_dns_reply *r; 98178825Sdfr const char **labels; 99178825Sdfr char **config_labels; 100102644Snectar int i, ret; 101233294Sstas 102178825Sdfr config_labels = krb5_config_get_strings(context, NULL, "libdefaults", 103178825Sdfr "dns_lookup_realm_labels", NULL); 104178825Sdfr if(config_labels != NULL) 105178825Sdfr labels = (const char **)config_labels; 106178825Sdfr else 107102644Snectar labels = default_labels; 10855682Smarkm if(*domain == '.') 10955682Smarkm domain++; 110102644Snectar for (i = 0; labels[i] != NULL; i++) { 111178825Sdfr ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); 112233294Sstas if(ret < 0 || (size_t)ret >= sizeof(dom)) { 113178825Sdfr if (config_labels) 114178825Sdfr krb5_config_free_strings(config_labels); 115102644Snectar return -1; 116178825Sdfr } 117233294Sstas r = rk_dns_lookup(dom, "TXT"); 118102644Snectar if(r != NULL) { 119102644Snectar ret = copy_txt_to_realms (r->head, realms); 120233294Sstas rk_dns_free_data(r); 121178825Sdfr if(ret == 0) { 122178825Sdfr if (config_labels) 123178825Sdfr krb5_config_free_strings(config_labels); 124102644Snectar return 0; 125178825Sdfr } 126102644Snectar } 127102644Snectar } 128178825Sdfr if (config_labels) 129178825Sdfr krb5_config_free_strings(config_labels); 130102644Snectar return -1; 13155682Smarkm} 13255682Smarkm 13355682Smarkm/* 13455682Smarkm * Try to figure out what realms host in `domain' belong to from the 13555682Smarkm * configuration file. 13655682Smarkm */ 13755682Smarkm 13855682Smarkmstatic int 139233294Sstasconfig_find_realm(krb5_context context, 140233294Sstas const char *domain, 14155682Smarkm krb5_realm **realms) 14255682Smarkm{ 14355682Smarkm char **tmp = krb5_config_get_strings (context, NULL, 14455682Smarkm "domain_realm", 14555682Smarkm domain, 14655682Smarkm NULL); 14755682Smarkm 14855682Smarkm if (tmp == NULL) 14955682Smarkm return -1; 15055682Smarkm *realms = tmp; 15155682Smarkm return 0; 15255682Smarkm} 15355682Smarkm 15455682Smarkm/* 15555682Smarkm * This function assumes that `host' is a FQDN (and doesn't handle the 15655682Smarkm * special case of host == NULL either). 15755682Smarkm * Try to find mapping in the config file or DNS and it that fails, 15855682Smarkm * fall back to guessing 15955682Smarkm */ 16055682Smarkm 161233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 162178825Sdfr_krb5_get_host_realm_int (krb5_context context, 163178825Sdfr const char *host, 164178825Sdfr krb5_boolean use_dns, 165178825Sdfr krb5_realm **realms) 16655682Smarkm{ 167102644Snectar const char *p, *q; 168102644Snectar krb5_boolean dns_locate_enable; 16955682Smarkm 170102644Snectar dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, 171102644Snectar "libdefaults", "dns_lookup_realm", NULL); 17255682Smarkm for (p = host; p != NULL; p = strchr (p + 1, '.')) { 173102644Snectar if(config_find_realm(context, p, realms) == 0) { 174102644Snectar if(strcasecmp(*realms[0], "dns_locate") == 0) { 175102644Snectar if(use_dns) 176102644Snectar for (q = host; q != NULL; q = strchr(q + 1, '.')) 177102644Snectar if(dns_find_realm(context, q, realms) == 0) 178102644Snectar return 0; 179233294Sstas continue; 180233294Sstas } else 181102644Snectar return 0; 182102644Snectar } 183102644Snectar else if(use_dns && dns_locate_enable) { 184102644Snectar if(dns_find_realm(context, p, realms) == 0) 18578527Sassar return 0; 18678527Sassar } 18755682Smarkm } 18855682Smarkm p = strchr(host, '.'); 18955682Smarkm if(p != NULL) { 19055682Smarkm p++; 19155682Smarkm *realms = malloc(2 * sizeof(krb5_realm)); 19278527Sassar if (*realms == NULL) { 193233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 19455682Smarkm return ENOMEM; 19578527Sassar } 19655682Smarkm 19755682Smarkm (*realms)[0] = strdup(p); 19855682Smarkm if((*realms)[0] == NULL) { 19955682Smarkm free(*realms); 200233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 20155682Smarkm return ENOMEM; 20255682Smarkm } 20355682Smarkm strupr((*realms)[0]); 20455682Smarkm (*realms)[1] = NULL; 20555682Smarkm return 0; 20655682Smarkm } 207233294Sstas krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, 208233294Sstas N_("unable to find realm of host %s", ""), 209233294Sstas 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 218233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 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 236233294Sstas /* 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) { 251233294Sstas krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, 252233294Sstas N_("Unable to find realm of host %s", ""), 253233294Sstas host); 254178825Sdfr return KRB5_ERR_HOST_REALM_UNKNOWN; 255178825Sdfr } 256178825Sdfr } 257178825Sdfr return ret; 25855682Smarkm} 259