diff options
author | Nicolas Williams <nico@cryptonector.com> | 2021-05-13 00:43:26 -0500 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2024-05-13 12:47:47 -0400 |
commit | d035119c3b2b402f3ad49a4c7b6264826ea923bb (patch) | |
tree | d11952914a3be3f3971062bc0faf0949b1fe229f | |
parent | 6b74b6c18feab1f3d72d00ae412a93c6bfa4a00a (diff) | |
download | krb5-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.rst | 4 | ||||
-rw-r--r-- | doc/admin/realm_config.rst | 10 | ||||
-rw-r--r-- | src/include/k5-int.h | 1 | ||||
-rw-r--r-- | src/lib/krb5/os/dnssrv.c | 34 | ||||
-rw-r--r-- | src/lib/krb5/os/locate_kdc.c | 31 | ||||
-rw-r--r-- | src/lib/krb5/os/os-proto.h | 4 |
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); |