aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2021-05-13 00:43:26 -0500
committerGreg Hudson <ghudson@mit.edu>2024-05-13 12:47:47 -0400
commitd035119c3b2b402f3ad49a4c7b6264826ea923bb (patch)
treed11952914a3be3f3971062bc0faf0949b1fe229f
parent6b74b6c18feab1f3d72d00ae412a93c6bfa4a00a (diff)
downloadkrb5-d035119c3b2b402f3ad49a4c7b6264826ea923bb.zip
krb5-d035119c3b2b402f3ad49a4c7b6264826ea923bb.tar.gz
krb5-d035119c3b2b402f3ad49a4c7b6264826ea923bb.tar.bz2
Support site-local KDC discovery via DNS
Add the sitename realm variable. If set, service location via DNS will be attempted using the site name as specified in [MS-ADTS] 6.3.2.3, falling back to regular discovery on failure. [ghudson@mit.edu: made this strictly a realm variable; moved k5_get_sitename() to locate_kdc.c and made it take a krb5_data input; fixed a memory leak; corrected documentation changes; fleshed out commit message] ticket: 9124 (new)
-rw-r--r--doc/admin/conf_files/krb5_conf.rst4
-rw-r--r--doc/admin/realm_config.rst10
-rw-r--r--src/include/k5-int.h1
-rw-r--r--src/lib/krb5/os/dnssrv.c34
-rw-r--r--src/lib/krb5/os/locate_kdc.c31
-rw-r--r--src/lib/krb5/os/os-proto.h4
6 files changed, 74 insertions, 10 deletions
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index ab73a69..2a45b1e 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -551,6 +551,10 @@ following tags may be specified in the realm's subsection:
the updated database has not been propagated to the replica
servers yet. New in release 1.19.
+**sitename**
+ Specifies the name of the host's site for the purpose of DNS-based
+ KDC discovery for this realm. New in release 1.22.
+
**v4_instance_convert**
This subsection allows the administrator to configure exceptions
to the **default_domain** mapping rule. It contains V4 instances
diff --git a/doc/admin/realm_config.rst b/doc/admin/realm_config.rst
index 35e4857..d0ed6f0 100644
--- a/doc/admin/realm_config.rst
+++ b/doc/admin/realm_config.rst
@@ -195,6 +195,13 @@ using the **kdc**, **master_kdc**, **admin_server**, and
explicit server locations, providing SRV records will still benefit
unconfigured clients, and be useful for other sites.
+Clients can be configured with the **sitename** realm variable (new in
+release 1.22). If a site name is set, the client first attempts SRV
+record lookups with ".*sitename*._sites" inserted after the service
+and protocol name and before the Kerberos realm. Site-specific
+records may indicate servers more proximal to the client, allowing for
+faster access.
+
.. _kdc_discovery:
@@ -243,6 +250,9 @@ URI lookups are enabled by default, and can be disabled by setting
precedence over SRV lookups, falling back to SRV lookups if no URI
records are found.
+The **sitename** variable in the :ref:`realms` section of
+:ref:`krb5.conf(5)` applies to URI lookups as well as SRV lookups.
+
.. _db_prop:
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index fe99593..a5763bf 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -293,6 +293,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_REJECT_BAD_TRANSIT "reject_bad_transit"
#define KRB5_CONF_RENEW_LIFETIME "renew_lifetime"
#define KRB5_CONF_RESTRICT_ANONYMOUS_TO_TGT "restrict_anonymous_to_tgt"
+#define KRB5_CONF_SITENAME "sitename"
#define KRB5_CONF_SUPPORTED_ENCTYPES "supported_enctypes"
#define KRB5_CONF_SPAKE_PREAUTH_INDICATOR "spake_preauth_indicator"
#define KRB5_CONF_SPAKE_PREAUTH_KDC_CHALLENGE "spake_preauth_kdc_challenge"
diff --git a/src/lib/krb5/os/dnssrv.c b/src/lib/krb5/os/dnssrv.c
index 62d6d13..ffbbc85 100644
--- a/src/lib/krb5/os/dnssrv.c
+++ b/src/lib/krb5/os/dnssrv.c
@@ -46,10 +46,10 @@ krb5int_free_srv_dns_data (struct srv_dns_entry *p)
}
/* Construct a DNS label of the form "service.[protocol.]realm.". protocol may
- * be NULL. */
+ * and/or sitename be NULL. */
static char *
make_lookup_name(const krb5_data *realm, const char *service,
- const char *protocol)
+ const char *protocol, const char *sitename)
{
struct k5buf buf;
@@ -60,6 +60,8 @@ make_lookup_name(const krb5_data *realm, const char *service,
k5_buf_add_fmt(&buf, "%s.", service);
if (protocol != NULL)
k5_buf_add_fmt(&buf, "%s.", protocol);
+ if (sitename != NULL)
+ k5_buf_add_fmt(&buf, "%s._sites.", sitename);
k5_buf_add_len(&buf, realm->data, realm->length);
/*
@@ -119,6 +121,7 @@ k5_make_uri_query(krb5_context context, const krb5_data *realm,
krb5_error_code
krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
const char *service, const char *protocol,
+ const char *sitename,
struct srv_dns_entry **answers)
{
char *name = NULL;
@@ -128,7 +131,7 @@ krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
*answers = NULL;
- name = make_lookup_name(realm, service, protocol);
+ name = make_lookup_name(realm, service, protocol, sitename);
if (name == NULL)
return 0;
@@ -136,6 +139,12 @@ krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
st = DnsQuery_UTF8(name, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &records,
NULL);
+ if (st != ERROR_SUCCESS && sitename != NULL) {
+ /* Try again without the site name. */
+ free(name);
+ return krb5int_make_srv_query_realm(context, realm, service, protocol,
+ NULL, answers);
+ }
if (st != ERROR_SUCCESS)
return 0;
@@ -176,7 +185,8 @@ cleanup:
/* Query the URI RR, collecting weight, priority, and target. */
krb5_error_code
k5_make_uri_query(krb5_context context, const krb5_data *realm,
- const char *service, struct srv_dns_entry **answers)
+ const char *service, const char *sitename,
+ struct srv_dns_entry **answers)
{
const unsigned char *p = NULL, *base = NULL;
char *name = NULL;
@@ -188,13 +198,18 @@ k5_make_uri_query(krb5_context context, const krb5_data *realm,
*answers = NULL;
/* Construct service.realm. */
- name = make_lookup_name(realm, service, NULL);
+ name = make_lookup_name(realm, service, NULL, sitename);
if (name == NULL)
return 0;
TRACE_DNS_URI_SEND(context, name);
size = krb5int_dns_init(&ds, name, C_IN, T_URI);
+ if (size < 0 && sitename != NULL) {
+ /* Try again without the site name. */
+ free(name);
+ return k5_make_uri_query(context, realm, service, NULL, answers);
+ }
if (size < 0)
goto out;
@@ -242,6 +257,7 @@ out:
krb5_error_code
krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
const char *service, const char *protocol,
+ const char *sitename,
struct srv_dns_entry **answers)
{
const unsigned char *p = NULL, *base = NULL;
@@ -262,13 +278,19 @@ krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
*
*/
- name = make_lookup_name(realm, service, protocol);
+ name = make_lookup_name(realm, service, protocol, sitename);
if (name == NULL)
return 0;
TRACE_DNS_SRV_SEND(context, name);
size = krb5int_dns_init(&ds, name, C_IN, T_SRV);
+ if (size < 0 && sitename) {
+ /* Try again without the site name. */
+ free(name);
+ return krb5int_make_srv_query_realm(context, realm, service, protocol,
+ NULL, answers);
+ }
if (size < 0)
goto out;
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index 7d246ef..e6f6e5f 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -98,6 +98,22 @@ _krb5_use_dns_realm(krb5_context context)
DEFAULT_LOOKUP_REALM);
}
+static krb5_error_code
+get_sitename(krb5_context context, const krb5_data *realm, char **out)
+{
+ krb5_error_code ret;
+ char *realmstr;
+
+ *out = NULL;
+ realmstr = k5memdup0(realm->data, realm->length, &ret);
+ if (realmstr == NULL)
+ return ret;
+ ret = profile_get_string(context->profile, KRB5_CONF_REALMS,
+ realmstr, KRB5_CONF_SITENAME, NULL, out);
+ free(realmstr);
+ return ret;
+}
+
#endif /* KRB5_DNS_LOOKUP */
/* Free up everything pointed to by the serverlist structure, but don't
@@ -328,9 +344,14 @@ locate_srv_dns_1(krb5_context context, const krb5_data *realm,
struct srv_dns_entry *head = NULL, *entry = NULL;
krb5_error_code code = 0;
k5_transport transport;
+ char *sitename;
+ code = get_sitename(context, realm, &sitename);
+ if (code)
+ return code;
code = krb5int_make_srv_query_realm(context, realm, service, protocol,
- &head);
+ sitename, &head);
+ free(sitename);
if (code)
return 0;
@@ -616,11 +637,15 @@ locate_uri(krb5_context context, const krb5_data *realm,
krb5_error_code ret;
k5_transport transport, host_trans;
struct srv_dns_entry *answers, *entry;
- char *host;
+ char *host, *sitename;
const char *host_field, *path;
int port, def_port, primary;
- ret = k5_make_uri_query(context, realm, req_service, &answers);
+ ret = get_sitename(context, realm, &sitename);
+ if (ret)
+ return ret;
+ ret = k5_make_uri_query(context, realm, req_service, sitename, &answers);
+ free(sitename);
if (ret || answers == NULL)
return ret;
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index ad686a9..a21558d 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -176,13 +176,15 @@ struct srv_dns_entry {
krb5_error_code
krb5int_make_srv_query_realm(krb5_context context, const krb5_data *realm,
const char *service, const char *protocol,
+ const char *sitename,
struct srv_dns_entry **answers);
void krb5int_free_srv_dns_data(struct srv_dns_entry *);
krb5_error_code
k5_make_uri_query(krb5_context context, const krb5_data *realm,
- const char *service, struct srv_dns_entry **answers);
+ const char *service, const char *sitename,
+ struct srv_dns_entry **answers);
krb5_error_code k5_try_realm_txt_rr(krb5_context context, const char *prefix,
const char *name, char **realm);