diff options
Diffstat (limited to 'lib/krb5/get_host_realm.c')
-rw-r--r-- | lib/krb5/get_host_realm.c | 156 |
1 files changed, 99 insertions, 57 deletions
diff --git a/lib/krb5/get_host_realm.c b/lib/krb5/get_host_realm.c index ed7f54b3d698..955d5462d418 100644 --- a/lib/krb5/get_host_realm.c +++ b/lib/krb5/get_host_realm.c @@ -49,8 +49,10 @@ */ static int -copy_txt_to_realms (struct rk_resource_record *head, - krb5_realm **realms) +copy_txt_to_realms(krb5_context context, + const char *domain, + struct rk_resource_record *head, + krb5_realm **realms) { struct rk_resource_record *rr; unsigned int n, i; @@ -64,21 +66,36 @@ copy_txt_to_realms (struct rk_resource_record *head, *realms = malloc ((n + 1) * sizeof(krb5_realm)); if (*realms == NULL) - return -1; + return krb5_enomem(context);; for (i = 0; i < n + 1; ++i) (*realms)[i] = NULL; for (i = 0, rr = head; rr; rr = rr->next) { if (rr->type == rk_ns_t_txt) { - char *tmp; + char *tmp = NULL; + int invalid_tld = 1; - tmp = strdup(rr->u.txt); + /* Check for a gTLD controlled interruption */ + if (strcmp("Your DNS configuration needs immediate " + "attention see https://icann.org/namecollision", + rr->u.txt) != 0) { + invalid_tld = 0; + tmp = strdup(rr->u.txt); + } if (tmp == NULL) { for (i = 0; i < n; ++i) free ((*realms)[i]); free (*realms); - return -1; + if (invalid_tld) { + krb5_warnx(context, + "Realm lookup failed: " + "Domain '%s' needs immediate attention " + "see https://icann.org/namecollision", + domain); + return KRB5_KDC_UNREACH; + } + return krb5_enomem(context);; } (*realms)[i] = tmp; ++i; @@ -97,7 +114,7 @@ dns_find_realm(krb5_context context, struct rk_dns_reply *r; const char **labels; char **config_labels; - int i, ret; + int i, ret = 0; config_labels = krb5_config_get_strings(context, NULL, "libdefaults", "dns_lookup_realm_labels", NULL); @@ -110,24 +127,26 @@ dns_find_realm(krb5_context context, for (i = 0; labels[i] != NULL; i++) { ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); if(ret < 0 || (size_t)ret >= sizeof(dom)) { - if (config_labels) - krb5_config_free_strings(config_labels); - return -1; + ret = krb5_enomem(context); + goto out; } r = rk_dns_lookup(dom, "TXT"); if(r != NULL) { - ret = copy_txt_to_realms (r->head, realms); + ret = copy_txt_to_realms(context, domain, r->head, realms); rk_dns_free_data(r); - if(ret == 0) { - if (config_labels) - krb5_config_free_strings(config_labels); - return 0; - } + if(ret == 0) + goto out; } } + krb5_set_error_message(context, KRB5_KDC_UNREACH, + "Realm lookup failed: " + "No DNS TXT record for %s", + domain); + ret = KRB5_KDC_UNREACH; +out: if (config_labels) krb5_config_free_strings(config_labels); - return -1; + return ret; } /* @@ -159,55 +178,78 @@ config_find_realm(krb5_context context, */ 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) +_krb5_get_host_realm_int(krb5_context context, + const char *host, + krb5_boolean use_dns, + krb5_realm **realms) { const char *p, *q; + const char *port; krb5_boolean dns_locate_enable; + krb5_error_code ret = 0; + + /* Strip off any trailing ":port" suffix. */ + port = strchr(host, ':'); + if (port != NULL) { + host = strndup(host, port - host); + if (host == NULL) + return krb5_enomem(context); + } dns_locate_enable = krb5_config_get_bool_default(context, NULL, TRUE, - "libdefaults", "dns_lookup_realm", NULL); + "libdefaults", "dns_lookup_realm", NULL); for (p = host; p != NULL; p = strchr (p + 1, '.')) { - if(config_find_realm(context, p, realms) == 0) { - if(strcasecmp(*realms[0], "dns_locate") == 0) { - if(use_dns) - for (q = host; q != NULL; q = strchr(q + 1, '.')) - if(dns_find_realm(context, q, realms) == 0) - return 0; - continue; - } else - return 0; - } - else if(use_dns && dns_locate_enable) { - if(dns_find_realm(context, p, realms) == 0) - return 0; - } + if (config_find_realm(context, p, realms) == 0) { + if (strcasecmp(*realms[0], "dns_locate") != 0) + break; + krb5_free_host_realm(context, *realms); + *realms = NULL; + if (!use_dns) + continue; + for (q = host; q != NULL; q = strchr(q + 1, '.')) + if (dns_find_realm(context, q, realms) == 0) + break; + if (q) + break; + } else if (use_dns && dns_locate_enable) { + if (dns_find_realm(context, p, realms) == 0) + break; + } } - p = strchr(host, '.'); - if(p != NULL) { - p++; - *realms = malloc(2 * sizeof(krb5_realm)); - if (*realms == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - (*realms)[0] = strdup(p); - if((*realms)[0] == NULL) { - free(*realms); - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - strupr((*realms)[0]); - (*realms)[1] = NULL; - return 0; + /* + * If 'p' is NULL, we did not find an explicit realm mapping in either the + * configuration file or DNS. Try the hostname suffix as a last resort. + * + * XXX: If we implement a KDC-specific variant of this function just for + * referrals, we could check whether we have a cross-realm TGT for the + * realm in question, and if not try the parent (loop again). + */ + if (p == NULL) { + p = strchr(host, '.'); + if (p != NULL) { + p++; + *realms = malloc(2 * sizeof(krb5_realm)); + if (*realms != NULL && + ((*realms)[0] = strdup(p)) != NULL) { + strupr((*realms)[0]); + (*realms)[1] = NULL; + } else { + free(*realms); + ret = krb5_enomem(context); + } + } else { + krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, + N_("unable to find realm of host %s", ""), + host); + ret = KRB5_ERR_HOST_REALM_UNKNOWN; + } } - krb5_set_error_message(context, KRB5_ERR_HOST_REALM_UNKNOWN, - N_("unable to find realm of host %s", ""), - host); - return KRB5_ERR_HOST_REALM_UNKNOWN; + + /* If 'port' is not NULL, we have a copy of 'host' to free. */ + if (port) + free((void *)host); + return ret; } /* |