krb5 commit: Default dns_canonicalize_hostname to "fallback"

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/edf56aad3eb7787540252e92177f672aa6e4a407
commit edf56aad3eb7787540252e92177f672aa6e4a407
Author: Greg Hudson <[email protected]>
Date:   Wed May 27 18:48:35 2020 -0400

    Default dns_canonicalize_hostname to "fallback"
    
    This change should mitigate some of the pain caused by the rdns=true
    default (generally associated with unwanted PTR records that cannot
    easily be changed), with a minimum of fallout.
    
    Update the documentation and tests accordingly.  In test environments,
    disable qualify_shortname and use the uncanonicalized system hostname
    (lowercased) to match the initial sn2princ result.
    
    ticket: 8911 (new)

 doc/admin/appl_servers.rst                      |   14 +++----
 doc/admin/conf_files/krb5_conf.rst              |    9 ++--
 doc/admin/princ_dns.rst                         |   50 +++++++++++++---------
 src/kadmin/testing/proto/krb5.conf.proto        |    8 ++--
 src/kadmin/testing/scripts/env-setup.shin       |    4 +-
 src/kadmin/testing/scripts/init_db              |    3 +-
 src/kadmin/testing/scripts/start_servers        |    3 +-
 src/kadmin/testing/scripts/start_servers_local  |    2 +-
 src/lib/kadm5/unit-test/api.current/init-v2.exp |    6 +--
 src/lib/krb5/krb/init_ctx.c                     |    2 +-
 src/tests/dejagnu/config/default.exp            |    5 +-
 src/tests/t_sn2princ.py                         |    5 +-
 src/util/k5test.py                              |   25 +++---------
 13 files changed, 61 insertions(+), 75 deletions(-)

diff --git a/doc/admin/appl_servers.rst b/doc/admin/appl_servers.rst
index 5232db9..afdf302 100644
--- a/doc/admin/appl_servers.rst
+++ b/doc/admin/appl_servers.rst
@@ -115,14 +115,12 @@ Getting DNS information correct
 -------------------------------
 
 Several aspects of Kerberos rely on name service.  When a hostname is
-used to name a service, the Kerberos library canonicalizes the
-hostname using forward and reverse name resolution.  (The reverse name
-resolution step can be turned off using the **rdns** variable in
-:ref:`libdefaults`.)  The result of this canonicalization must match
-the principal entry in the host's keytab, or authentication will fail.
-
-Each host's canonical name must be the fully-qualified host name
-(including the domain), and each host's IP address must
+used to name a service, clients may canonicalize the hostname using
+forward and possibly reverse name resolution.  The result of this
+canonicalization must match the principal entry in the host's keytab,
+or authentication will fail.  To work with all client canonicalization
+configurations, each host's canonical name must be the fully-qualified
+host name (including the domain), and each host's IP address must
 reverse-resolve to the canonical name.
 
 Configuration of hostnames varies by operating system.  On the
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
index 1d8ffc1..7f28796 100644
--- a/doc/admin/conf_files/krb5_conf.rst
+++ b/doc/admin/conf_files/krb5_conf.rst
@@ -188,11 +188,10 @@ The libdefaults section may contain any of the following relations:
     hostnames for use in service principal names.  Setting this flag
     to false can improve security by reducing reliance on DNS, but
     means that short hostnames will not be canonicalized to
-    fully-qualified hostnames.  The default value is true.
-
-    If this option is set to ``fallback`` (new in release 1.18), DNS
-    canonicalization will only be performed the server hostname is not
-    found with the original name when requesting credentials.
+    fully-qualified hostnames.  If this option is set to ``fallback`` (new
+    in release 1.18), DNS canonicalization will only be performed the
+    server hostname is not found with the original name when
+    requesting credentials.  The default value is ``fallback``.
 
 **dns_lookup_kdc**
     Indicate whether DNS SRV records should be used to locate the KDCs
diff --git a/doc/admin/princ_dns.rst b/doc/admin/princ_dns.rst
index e1d823f..32a269a 100644
--- a/doc/admin/princ_dns.rst
+++ b/doc/admin/princ_dns.rst
@@ -31,27 +31,35 @@ based on rotating ``CNAME`` records in DNS.
 Service principal canonicalization
 ----------------------------------
 
-MIT Kerberos clients currently always do forward resolution (looking
-up the IPv4 and possibly IPv6 addresses using ``getaddrinfo()``) of
-the hostname part of a host-based service principal to canonicalize
-the hostname.  They obtain the "canonical" name of the host when doing
-so.  By default, MIT Kerberos clients will also then do reverse DNS
-resolution (looking up the hostname associated with the IPv4 or IPv6
-address using ``getnameinfo()``) of the hostname.  Using the
-:ref:`krb5.conf(5)` setting::
+In the MIT krb5 client library, canonicalization of host-based service
+principals is controlled by the **dns_canonicalize_hostname**,
+**rnds**, and **qualify_shortname** variables in :ref:`libdefaults`.
+
+If **dns_canonicalize_hostname** is set to ``true`` (the default value
+before release 1.19), the client performs forward resolution by
+looking up the IPv4 and/or IPv6 addresses of the hostname using
+``getaddrinfo()``.  This process will typically add a domain suffix to
+the hostname if needed, and follow CNAME records in the DNS.  If
+**rdns** is also set to ``true`` (the default), the client will then
+perform a reverse lookup of the first returned Internet address using
+``getnameinfo()``, finding the name associated with the PTR record.
+
+If **dns_canonicalize_hostname** is set to ``false``, the hostname is
+not canonicalized using DNS.  If the hostname has only one component
+(i.e. it contains no "." characters), the host's primary DNS search
+domain will be appended, if there is one.  The **qualify_shortname**
+variable can be used to override or disable this suffix.
+
+If **dns_canonicalize_hostname** is set to ``fallback`` (the default
+value in release 1.19 and later), the hostname is initially treated
+according to the rules for ``dns_canonicalize_hostname=false``.  If a
+ticket request fails because the service principal is unknown, it the
+hostname will be canonicalized according to the rules for
+``dns_canonicalize_hostname=true`` and the request will be retried.
+
+In all cases, the hostname is converted to lowercase, and any trailing
+dot is removed.
 
-    [libdefaults]
-        rdns = false
-
-will disable reverse DNS lookup on clients.  The default setting is
-"true".
-
-Operating system bugs may prevent a setting of ``rdns = false`` from
-disabling reverse DNS lookup.  Some versions of GNU libc have a bug in
-``getaddrinfo()`` that cause them to look up ``PTR`` records even when
-not required.  MIT Kerberos releases krb5-1.10.2 and newer have a
-workaround for this problem, as does the krb5-1.9.x series as of
-release krb5-1.9.4.
 
 
 Reverse DNS mismatches
diff --git a/src/kadmin/testing/proto/krb5.conf.proto b/src/kadmin/testing/proto/krb5.conf.proto
index e710852..c0af716 100644
--- a/src/kadmin/testing/proto/krb5.conf.proto
+++ b/src/kadmin/testing/proto/krb5.conf.proto
@@ -2,19 +2,19 @@
 	default_realm = __REALM__
 	default_keytab_name = FILE:__K5ROOT__/keytab
 	dns_fallback = no
+	qualify_shortname = ""
 	plugin_base_dir = __PLUGIN_DIR__
 	allow_weak_crypto = true
 
 [realms]
 	__REALM__ = {
-		kdc = __KDCHOST__:1750
-		admin_server = __KDCHOST__:1751
+		kdc = __HOSTNAME__:1750
+		admin_server = __HOSTNAME__:1751
 		database_module = foobar_db2_module_blah
 	}
 
 [domain_realm]
-	__LOCALHOST__ = __REALM__
-	__KDCHOST__ = __REALM__
+	__HOSTNAME__ = __REALM__
 
 [logging]
 	admin_server = FILE:__K5ROOT__/syslog
diff --git a/src/kadmin/testing/scripts/env-setup.shin b/src/kadmin/testing/scripts/env-setup.shin
index 969c534..88f8ad1 100755
--- a/src/kadmin/testing/scripts/env-setup.shin
+++ b/src/kadmin/testing/scripts/env-setup.shin
@@ -71,8 +71,8 @@ BSDDB_DUMP=$TESTDIR/util/bsddb_dump; export BSDDB_DUMP
 CLNTTCL=$TESTDIR/util/kadm5_clnt_tcl; export CLNTTCL
 SRVTCL=$TESTDIR/util/kadm5_srv_tcl; export SRVTCL
 
-QUALNAME=`$BUILDTOP/tests/resolve/resolve -q | tr '[A-Z]' '[a-z]'`
-export QUALNAME
+HOSTNAME=`hostname | tr '[A-Z]' '[a-z]'`
+export HOSTNAME
 
 KRB5_CONFIG=$K5ROOT/krb5.conf; export KRB5_CONFIG
 KRB5_KDC_PROFILE=$K5ROOT/kdc.conf; export KRB5_KDC_PROFILE
diff --git a/src/kadmin/testing/scripts/init_db b/src/kadmin/testing/scripts/init_db
index e65826c..216f627 100755
--- a/src/kadmin/testing/scripts/init_db
+++ b/src/kadmin/testing/scripts/init_db
@@ -79,8 +79,7 @@ fi
 # done
 
 sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
-	-e "s/__KDCHOST__/$QUALNAME/g" \
-	-e "s/__LOCALHOST__/$QUALNAME/g" \
+	-e "s/__HOSTNAME__/$HOSTNAME/g" \
 	-e "s#__MODDIR__#$MODDIR#g" \
 	< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
 sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
diff --git a/src/kadmin/testing/scripts/start_servers b/src/kadmin/testing/scripts/start_servers
index f23df06..05519e4 100755
--- a/src/kadmin/testing/scripts/start_servers
+++ b/src/kadmin/testing/scripts/start_servers
@@ -36,8 +36,7 @@ if [ $local = 0 ]; then
 
 	# Fix up the local krb5.conf to point to the remote 
 	sed -e "s/__REALM__/$REALM/g" -e "s#__K5ROOT__#$K5ROOT#g" \
-		-e "s/__KDCHOST__/$hostname/g" \
-		-e "s/__LOCALHOST__/$QUALNAME/g" \
+		-e "s/__HOSTNAME__/$HOSTNAME/g" \
 		-e "s#__MODDIR__#$TOP/../plugins/kdb#g"\
 		-e "s#__PLUGIN_DIR__#$TOP/../plugins#g"\
 		< $STESTDIR/proto/krb5.conf.proto > $K5ROOT/krb5.conf
diff --git a/src/kadmin/testing/scripts/start_servers_local b/src/kadmin/testing/scripts/start_servers_local
index 998ef91..858e880 100755
--- a/src/kadmin/testing/scripts/start_servers_local
+++ b/src/kadmin/testing/scripts/start_servers_local
@@ -79,7 +79,7 @@ cat - > /tmp/start_servers_local$$ <<\EOF
 if { [catch {
 	source $env(STOP)/testing/tcl/util.t
 	set r $env(REALM)
-	set q $env(QUALNAME)
+	set q $env(HOSTNAME)
 	puts stdout [kadm5_init $env(SRVTCL) mrroot null \
 		[config_params {KADM5_CONFIG_REALM} $r] \
 		$KADM5_STRUCT_VERSION $KADM5_API_VERSION_3 server_handle]
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/unit-test/api.current/init-v2.exp
index 7a353d4..47764c2 100644
--- a/src/lib/kadm5/unit-test/api.current/init-v2.exp
+++ b/src/lib/kadm5/unit-test/api.current/init-v2.exp
@@ -3,18 +3,14 @@ load_lib lib.t
 api_exit
 api_start
 
-if ![info exists RESOLVE] {
-    set RESOLVE [findfile $objdir/../../../tests/resolve/resolve]
-}
 proc get_hostname { } {
-    global RESOLVE
     global hostname
 
     if {[info exists hostname]} {
 	return 1
     }
 
-    catch "exec $RESOLVE -q >myname" exec_output
+    catch "exec hostname >myname" exec_output
     if ![string match "" $exec_output] {
 	send_log "$exec_output\n"
 	verbose $exec_output
diff --git a/src/lib/krb5/krb/init_ctx.c b/src/lib/krb5/krb/init_ctx.c
index be31eb3..21d5cb1 100644
--- a/src/lib/krb5/krb/init_ctx.c
+++ b/src/lib/krb5/krb/init_ctx.c
@@ -238,7 +238,7 @@ krb5_init_context_profile(profile_t profile, krb5_flags flags,
     ctx->enforce_ok_as_delegate = tmp;
 
     retval = get_tristate(ctx, KRB5_CONF_DNS_CANONICALIZE_HOSTNAME, "fallback",
-                          CANONHOST_FALLBACK, 1, &tmp);
+                          CANONHOST_FALLBACK, CANONHOST_FALLBACK, &tmp);
     if (retval)
         goto cleanup;
     ctx->dns_canonicalize_hostname = tmp;
diff --git a/src/tests/dejagnu/config/default.exp b/src/tests/dejagnu/config/default.exp
index f5536c6..619fcce 100644
--- a/src/tests/dejagnu/config/default.exp
+++ b/src/tests/dejagnu/config/default.exp
@@ -303,7 +303,6 @@ foreach i {
     {KTUTIL $objdir/../../kadmin/ktutil/ktutil}
     {KLIST $objdir/../../clients/klist/klist}
     {KDESTROY $objdir/../../clients/kdestroy/kdestroy}
-    {RESOLVE $objdir/../resolve/resolve}
     {T_INETD $objdir/t_inetd}
     {KPROPLOG $objdir/../../kprop/kproplog}
     {KPASSWD $objdir/../../clients/kpasswd/kpasswd}
@@ -497,7 +496,6 @@ proc setup_runtime_env { } {
 # 0 on failure.
 
 proc get_hostname { } {
-    global RESOLVE
     global hostname
     global tmppwd
 
@@ -507,7 +505,7 @@ proc get_hostname { } {
 
     envstack_push
     setup_runtime_env
-    catch "exec $RESOLVE -q >$tmppwd/hostname" exec_output
+    catch "exec hostname >$tmppwd/hostname" exec_output
     envstack_pop
     if ![string match "" $exec_output] {
 	verbose -log $exec_output
@@ -745,6 +743,7 @@ proc setup_krb5_conf { {type client} } {
 	puts $conffile "\[libdefaults\]"
 	puts $conffile "	default_realm = $REALMNAME"
 	puts $conffile "	dns_lookup_kdc = false"
+	puts $conffile "	qualify_shortname = \"\""
 	if [info exists allow_weak_crypto($type)] {
 	    puts $conffile "	allow_weak_crypto = $allow_weak_crypto($type)"
 	} else {
diff --git a/src/tests/t_sn2princ.py b/src/tests/t_sn2princ.py
index f1b21c5..ca94af4 100755
--- a/src/tests/t_sn2princ.py
+++ b/src/tests/t_sn2princ.py
@@ -2,7 +2,8 @@ from k5test import *
 
 offline = (len(args) > 0 and args[0] != "no")
 
-conf = {'domain_realm': {'kerberos.org': 'R1',
+conf = {'libdefaults': {'dns_canonicalize_hostname': 'true'},
+        'domain_realm': {'kerberos.org': 'R1',
                          'example.com': 'R2',
                          'mit.edu': 'R3'}}
 no_rdns_conf = {'libdefaults': {'rdns': 'false'}}
@@ -28,7 +29,7 @@ def testbase(host, nametype, princhost, princrealm, env=None):
         fail('Expected %s, got %s' % (expected, out))
 
 def test(host, princhost, princrealm):
-    # Test with the host-based name type in the default environment.
+    # Test with the host-based name type with canonicalization enabled.
     testbase(host, 'srv-hst', princhost, princrealm)
 
 def testnc(host, princhost, princrealm):
diff --git a/src/util/k5test.py b/src/util/k5test.py
index 442a4e4..e58c9fd 100644
--- a/src/util/k5test.py
+++ b/src/util/k5test.py
@@ -193,7 +193,10 @@ Scripts may use the following functions and variables:
 
 * plugins: The plugin directory in the build tree (absolute path).
 
-* hostname: This machine's fully-qualified domain name.
+* hostname: The local hostname as it will initially appear in
+  krb5_sname_to_principal() results.  (Shortname qualification is
+  turned off in the test environment to make this value easy to
+  discover from Python.)
 
 * null_input: A file opened to read /dev/null.
 
@@ -525,23 +528,6 @@ def _find_srctop():
     return os.path.abspath(root)
 
 
-# Return the local hostname as it will be canonicalized by
-# krb5_sname_to_principal.  We can't simply use socket.getfqdn()
-# because it explicitly prefers results containing periods and
-# krb5_sname_to_principal doesn't care.
-def _get_hostname():
-    hostname = socket.gethostname()
-    try:
-        ai = socket.getaddrinfo(hostname, None, 0, 0, 0, socket.AI_CANONNAME)
-    except socket.gaierror as e:
-        fail('Local hostname "%s" does not resolve: %s.' % (hostname, e[1]))
-    (family, socktype, proto, canonname, sockaddr) = ai[0]
-    try:
-        name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
-    except socket.gaierror:
-        return canonname.lower()
-    return name[0].lower()
-
 # Parse command line arguments, setting global option variables.  Also
 # sets the global variable args to the positional arguments, which may
 # be used by the test script.
@@ -1263,6 +1249,7 @@ _default_krb5_conf = {
     'libdefaults': {
         'default_realm': '$realm',
         'dns_lookup_kdc': 'false',
+        'qualify_shortname': '',
         'plugin_base_dir': '$plugins'},
     'realms': {'$realm': {
             'kdc': '$hostname:$port0',
@@ -1363,7 +1350,7 @@ buildtop = _find_buildtop()
 srctop = _find_srctop()
 plugins = os.path.join(buildtop, 'plugins')
 runenv = _import_runenv()
-hostname = _get_hostname()
+hostname = socket.gethostname().lower()
 null_input = open(os.devnull, 'r')
 
 # A DB pass is a tuple of: name, kdc_conf.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.