From 4aee4bdd71818b7b56b40f3d98305474f557d143 Mon Sep 17 00:00:00 2001 From: Robbie Harwood Date: Fri, 6 Dec 2019 13:44:42 -0500 Subject: [PATCH] Qualify short hostnames when not using DNS --- ...y-short-hostnames-when-not-using-DNS.patch | 309 ++++++++++++++++++ krb5.spec | 6 +- 2 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 Qualify-short-hostnames-when-not-using-DNS.patch diff --git a/Qualify-short-hostnames-when-not-using-DNS.patch b/Qualify-short-hostnames-when-not-using-DNS.patch new file mode 100644 index 0000000..2555b77 --- /dev/null +++ b/Qualify-short-hostnames-when-not-using-DNS.patch @@ -0,0 +1,309 @@ +From 35160d8bf1aa1464d7e757c73ed11644478cc4d4 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 29 Nov 2019 20:39:38 -0500 +Subject: [PATCH] Qualify short hostnames when not using DNS + +When DNS forward canonicalization is turned off or fails, qualify +single-component hostnames with the first DNS search domain. Add the +qualify_shortname relation to override this suffix. + +For one of the tests we need to disable qualification, which is +accomplished with an empty value. Adjust k5test.py to correctly emit +empty values when writing profiles. + +ticket: 8855 (new) +(cherry picked from commit 996353767fe8afa7f67a3b5b465e4d70e18bad7c) +--- + doc/admin/conf_files/krb5_conf.rst | 9 +++++++ + src/include/k5-int.h | 1 + + src/lib/krb5/os/dnsglue.c | 23 ++++++++++++++++ + src/lib/krb5/os/os-proto.h | 2 ++ + src/lib/krb5/os/sn2princ.c | 43 +++++++++++++++++++++++++++++- + src/tests/gssapi/t_ccselect.py | 5 ++-- + src/tests/t_sn2princ.py | 12 ++++++--- + src/util/k5test.py | 34 ++++++++++++----------- + 8 files changed, 106 insertions(+), 23 deletions(-) + +diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst +index 89f02434b..582ac8df0 100644 +--- a/doc/admin/conf_files/krb5_conf.rst ++++ b/doc/admin/conf_files/krb5_conf.rst +@@ -308,6 +308,15 @@ The libdefaults section may contain any of the following relations: + If this flag is true, initial tickets will be proxiable by + default, if allowed by the KDC. The default value is false. + ++**qualify_shortname** ++ If this string is set, it determines the domain suffix for ++ single-component hostnames when DNS canonicalization is not used ++ (either because **dns_canonicalize_hostname** is false or because ++ forward canonicalization failed). The default value is the first ++ search domain of the system's DNS configuration. To disable ++ qualification of shortnames, set this relation to the empty string ++ with ``qualify_shortname = ""``. (New in release 1.18.) ++ + **rdns** + If this flag is true, reverse name lookup will be used in addition + to forward name lookup to canonicalizing hostnames for use in +diff --git a/src/include/k5-int.h b/src/include/k5-int.h +index cb328785d..7458319fa 100644 +--- a/src/include/k5-int.h ++++ b/src/include/k5-int.h +@@ -280,6 +280,7 @@ typedef unsigned char u_char; + #define KRB5_CONF_PLUGIN_BASE_DIR "plugin_base_dir" + #define KRB5_CONF_PREFERRED_PREAUTH_TYPES "preferred_preauth_types" + #define KRB5_CONF_PROXIABLE "proxiable" ++#define KRB5_CONF_QUALIFY_SHORTNAME "qualify_shortname" + #define KRB5_CONF_RDNS "rdns" + #define KRB5_CONF_REALMS "realms" + #define KRB5_CONF_REALM_TRY_DOMAINS "realm_try_domains" +diff --git a/src/lib/krb5/os/dnsglue.c b/src/lib/krb5/os/dnsglue.c +index 59ff92963..e35ca9d76 100644 +--- a/src/lib/krb5/os/dnsglue.c ++++ b/src/lib/krb5/os/dnsglue.c +@@ -71,6 +71,7 @@ static int initparse(struct krb5int_dns_state *); + * Define macros to use the best available DNS search functions. INIT_HANDLE() + * returns true if handle initialization is successful, false if it is not. + * SEARCH() returns the length of the response or -1 on error. ++ * PRIMARY_DOMAIN() returns the first search domain in allocated memory. + * DECLARE_HANDLE() must be used last in the declaration list since it may + * evaluate to nothing. + */ +@@ -81,6 +82,7 @@ static int initparse(struct krb5int_dns_state *); + #define DECLARE_HANDLE(h) dns_handle_t h + #define INIT_HANDLE(h) ((h = dns_open(NULL)) != NULL) + #define SEARCH(h, n, c, t, a, l) dns_search(h, n, c, t, a, l, NULL, NULL) ++#define PRIMARY_DOMAIN(h) dns_search_list_domain(h, 0) + #define DESTROY_HANDLE(h) dns_free(h) + + #elif HAVE_RES_NINIT && HAVE_RES_NSEARCH +@@ -89,6 +91,7 @@ static int initparse(struct krb5int_dns_state *); + #define DECLARE_HANDLE(h) struct __res_state h + #define INIT_HANDLE(h) (memset(&h, 0, sizeof(h)), res_ninit(&h) == 0) + #define SEARCH(h, n, c, t, a, l) res_nsearch(&h, n, c, t, a, l) ++#define PRIMARY_DOMAIN(h) strdup(h.dnsrch[0]) + #if HAVE_RES_NDESTROY + #define DESTROY_HANDLE(h) res_ndestroy(&h) + #else +@@ -101,6 +104,7 @@ static int initparse(struct krb5int_dns_state *); + #define DECLARE_HANDLE(h) + #define INIT_HANDLE(h) (res_init() == 0) + #define SEARCH(h, n, c, t, a, l) res_search(n, c, t, a, l) ++#define PRIMARY_DOMAIN(h) strdup(_res.defdname) + #define DESTROY_HANDLE(h) + + #endif +@@ -433,6 +437,12 @@ cleanup: + return ret; + } + ++char * ++k5_primary_domain() ++{ ++ return NULL; ++} ++ + #else /* _WIN32 */ + + krb5_error_code +@@ -485,5 +495,18 @@ errout: + return retval; + } + ++char * ++k5_primary_domain() ++{ ++ char *domain; ++ DECLARE_HANDLE(h); ++ ++ if (!INIT_HANDLE(h)) ++ return NULL; ++ domain = PRIMARY_DOMAIN(h); ++ DESTROY_HANDLE(h); ++ return domain; ++} ++ + #endif /* not _WIN32 */ + #endif /* KRB5_DNS_LOOKUP */ +diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h +index 066d30221..a16a34b74 100644 +--- a/src/lib/krb5/os/os-proto.h ++++ b/src/lib/krb5/os/os-proto.h +@@ -136,6 +136,8 @@ k5_make_uri_query(krb5_context context, const krb5_data *realm, + krb5_error_code k5_try_realm_txt_rr(krb5_context context, const char *prefix, + const char *name, char **realm); + ++char *k5_primary_domain(void); ++ + int _krb5_use_dns_realm (krb5_context); + int _krb5_use_dns_kdc (krb5_context); + int _krb5_conf_boolean (const char *); +diff --git a/src/lib/krb5/os/sn2princ.c b/src/lib/krb5/os/sn2princ.c +index 98d2600aa..a51761d0c 100644 +--- a/src/lib/krb5/os/sn2princ.c ++++ b/src/lib/krb5/os/sn2princ.c +@@ -50,15 +50,47 @@ use_reverse_dns(krb5_context context) + &value); + if (ret) + return DEFAULT_RDNS_LOOKUP; ++ + return value; + } + ++/* Append a domain suffix to host and return the result in allocated memory. ++ * Return NULL if no suffix is configured or on failure. */ ++static char * ++qualify_shortname(krb5_context context, const char *host) ++{ ++ krb5_error_code ret; ++ char *fqdn = NULL, *prof_domain = NULL, *os_domain = NULL; ++ const char *domain; ++ ++ ret = profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS, ++ KRB5_CONF_QUALIFY_SHORTNAME, NULL, NULL, ++ &prof_domain); ++ if (ret) ++ return NULL; ++ ++#ifdef KRB5_DNS_LOOKUP ++ if (prof_domain == NULL) ++ os_domain = k5_primary_domain(); ++#endif ++ ++ domain = (prof_domain != NULL) ? prof_domain : os_domain; ++ if (domain != NULL && *domain != '\0') { ++ if (asprintf(&fqdn, "%s.%s", host, domain) < 0) ++ fqdn = NULL; ++ } ++ ++ profile_release_string(prof_domain); ++ free(os_domain); ++ return fqdn; ++} ++ + krb5_error_code + k5_expand_hostname(krb5_context context, const char *host, + krb5_boolean is_fallback, char **canonhost_out) + { + struct addrinfo *ai = NULL, hint; +- char namebuf[NI_MAXHOST], *copy, *p; ++ char namebuf[NI_MAXHOST], *qualified = NULL, *copy, *p; + int err; + const char *canonhost; + krb5_boolean use_dns; +@@ -90,6 +122,14 @@ k5_expand_hostname(krb5_context context, const char *host, + } + } + ++ /* If we didn't use DNS and the name is just one component, try to add a ++ * domain suffix. */ ++ if (canonhost == host && strchr(host, '.') == NULL) { ++ qualified = qualify_shortname(context, host); ++ if (qualified != NULL) ++ canonhost = qualified; ++ } ++ + copy = strdup(canonhost); + if (copy == NULL) + goto cleanup; +@@ -113,6 +153,7 @@ cleanup: + /* We only return success or ENOMEM. */ + if (ai != NULL) + freeaddrinfo(ai); ++ free(qualified); + return (*canonhost_out == NULL) ? ENOMEM : 0; + } + +diff --git a/src/tests/gssapi/t_ccselect.py b/src/tests/gssapi/t_ccselect.py +index 9ca66554f..66d85880c 100755 +--- a/src/tests/gssapi/t_ccselect.py ++++ b/src/tests/gssapi/t_ccselect.py +@@ -24,8 +24,9 @@ from k5test import * + + # Create two independent realms (no cross-realm TGTs). For the + # fallback realm tests we need to control the precise server hostname, +-# so turn off DNS canonicalization. +-conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}} ++# so turn off DNS canonicalization and shortname qualification. ++conf = {'libdefaults': {'dns_canonicalize_hostname': 'false', ++ 'qualify_shortname': ''}} + r1 = K5Realm(create_user=False, krb5_conf=conf) + r2 = K5Realm(create_user=False, krb5_conf=conf, realm='KRBTEST2.COM', + portbase=62000, testdir=os.path.join(r1.testdir, 'r2')) +diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py +index fe435a2d5..26dcb91c2 100755 +--- a/src/tests/t_sn2princ.py ++++ b/src/tests/t_sn2princ.py +@@ -6,7 +6,8 @@ conf = {'domain_realm': {'kerberos.org': 'R1', + 'example.com': 'R2', + 'mit.edu': 'R3'}} + no_rdns_conf = {'libdefaults': {'rdns': 'false'}} +-no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false'}} ++no_canon_conf = {'libdefaults': {'dns_canonicalize_hostname': 'false', ++ 'qualify_shortname': 'example.com'}} + fallback_canon_conf = {'libdefaults': + {'rdns': 'false', + 'dns_canonicalize_hostname': 'fallback'}} +@@ -62,12 +63,15 @@ testu('Example.COM:xyZ', 'Example.COM:xyZ', 'R2') + testu('example.com.::123', 'example.com.::123', '') + + # With dns_canonicalize_hostname=false, we downcase and remove +-# trailing dots but do not canonicalize the hostname. Trailers do not +-# get downcased. ++# trailing dots but do not canonicalize the hostname. ++# Single-component names are qualified with the configured suffix ++# (defaulting to the first OS search domain, but Python cannot easily ++# retrieve that value so we don't test it). Trailers do not get ++# downcased. + mark('dns_canonicalize_host=false') + testnc('ptr-mismatch.kerberos.org', 'ptr-mismatch.kerberos.org', 'R1') + testnc('Example.COM', 'example.com', 'R2') +-testnc('abcde', 'abcde', '') ++testnc('abcde', 'abcde.example.com', 'R2') + testnc('example.com.:123', 'example.com:123', 'R2') + testnc('Example.COM:xyZ', 'example.com:xyZ', 'R2') + testnc('example.com.::123', 'example.com.::123', '') +diff --git a/src/util/k5test.py b/src/util/k5test.py +index feb6df7a0..c7f941303 100644 +--- a/src/util/k5test.py ++++ b/src/util/k5test.py +@@ -918,22 +918,24 @@ class K5Realm(object): + def _subst_cfg_value(self, value): + global buildtop, srctop, hostname + template = string.Template(value) +- return template.substitute(realm=self.realm, +- testdir=self.testdir, +- buildtop=buildtop, +- srctop=srctop, +- plugins=plugins, +- hostname=hostname, +- port0=self.portbase, +- port1=self.portbase + 1, +- port2=self.portbase + 2, +- port3=self.portbase + 3, +- port4=self.portbase + 4, +- port5=self.portbase + 5, +- port6=self.portbase + 6, +- port7=self.portbase + 7, +- port8=self.portbase + 8, +- port9=self.portbase + 9) ++ subst = template.substitute(realm=self.realm, ++ testdir=self.testdir, ++ buildtop=buildtop, ++ srctop=srctop, ++ plugins=plugins, ++ hostname=hostname, ++ port0=self.portbase, ++ port1=self.portbase + 1, ++ port2=self.portbase + 2, ++ port3=self.portbase + 3, ++ port4=self.portbase + 4, ++ port5=self.portbase + 5, ++ port6=self.portbase + 6, ++ port7=self.portbase + 7, ++ port8=self.portbase + 8, ++ port9=self.portbase + 9) ++ # Empty values must be quoted to avoid a syntax error. ++ return subst if subst else '""' + + def _create_acl(self): + global hostname diff --git a/krb5.spec b/krb5.spec index 10c06e9..d2e903d 100644 --- a/krb5.spec +++ b/krb5.spec @@ -18,7 +18,7 @@ Summary: The Kerberos network authentication system Name: krb5 Version: 1.17 # for prerelease, should be e.g., 0.% {prerelease}.1% { ?dist } (without spaces) -Release: 53%{?dist} +Release: 54%{?dist} # lookaside-cached sources; two downloads and a build artifact Source0: https://web.mit.edu/kerberos/dist/krb5/1.17/krb5-%{version}%{prerelease}.tar.gz @@ -128,6 +128,7 @@ Patch169: Use-backported-version-of-OpenSSL-3-KDF-interface.patch Patch170: krb5-1.17post6-FIPS-with-PRNG-and-RADIUS-and-MD4.patch Patch171: Fix-kadmin-addprinc-randkey-kvno.patch Patch172: Various-gssalloc-fixes.patch +Patch173: Qualify-short-hostnames-when-not-using-DNS.patch License: MIT URL: https://web.mit.edu/kerberos/www/ @@ -735,6 +736,9 @@ exit 0 %{_libdir}/libkadm5srv_mit.so.* %changelog +* Fri Dec 06 2019 Robbie Harwood - 1.17-54 +- Qualify short hostnames when not using DNS + * Wed Nov 27 2019 Robbie Harwood - 1.17-53 - Various gssalloc fixes