krb5/Use-fallback-realm-for-GSSAPI-ccache-selection.patch
2017-06-23 20:45:16 +00:00

186 lines
7.3 KiB
Diff

From 4963152dc973e8ff74f257f64b0960a7716b480c Mon Sep 17 00:00:00 2001
From: Matt Rogers <mrogers@redhat.com>
Date: Fri, 10 Feb 2017 12:53:42 -0500
Subject: [PATCH] Use fallback realm for GSSAPI ccache selection
In krb5_cc_select(), if the server principal has an empty realm, use
krb5_get_fallback_host_realm() and set the server realm to the first
fallback found. This helps with the selection of a non-default ccache
when there is no [domain_realms] configuration for the server domain.
Modify t_ccselect.py tests to account for fallback behavior.
ticket: 8549 (new)
(cherry picked from commit 234b64bd6139d5b75dadd5abbd5bef5a162e298a)
---
src/lib/krb5/ccache/ccselect.c | 37 ++++++++++++++++++++++++++-----
src/tests/gssapi/t_ccselect.py | 50 +++++++++++++++++++++++++++++++++---------
2 files changed, 72 insertions(+), 15 deletions(-)
diff --git a/src/lib/krb5/ccache/ccselect.c b/src/lib/krb5/ccache/ccselect.c
index 2f3071a27..ee4b83a9b 100644
--- a/src/lib/krb5/ccache/ccselect.c
+++ b/src/lib/krb5/ccache/ccselect.c
@@ -132,6 +132,8 @@ krb5_cc_select(krb5_context context, krb5_principal server,
struct ccselect_module_handle **hp, *h;
krb5_ccache cache;
krb5_principal princ;
+ krb5_principal srvcp = NULL;
+ char **fbrealms = NULL;
*cache_out = NULL;
*princ_out = NULL;
@@ -139,7 +141,27 @@ krb5_cc_select(krb5_context context, krb5_principal server,
if (context->ccselect_handles == NULL) {
ret = load_modules(context);
if (ret)
- return ret;
+ goto cleanup;
+ }
+
+ /* Try to use the fallback host realm for the server if there is no
+ * authoritative realm. */
+ if (krb5_is_referral_realm(&server->realm) &&
+ server->type == KRB5_NT_SRV_HST && server->length == 2) {
+ ret = krb5_get_fallback_host_realm(context, &server->data[1],
+ &fbrealms);
+ if (ret)
+ goto cleanup;
+
+ /* Make a copy with the first fallback realm. */
+ ret = krb5_copy_principal(context, server, &srvcp);
+ if (ret)
+ goto cleanup;
+ ret = krb5_set_principal_realm(context, srvcp, fbrealms[0]);
+ if (ret)
+ goto cleanup;
+
+ server = srvcp;
}
/* Consult authoritative modules first, then heuristic ones. */
@@ -155,20 +177,25 @@ krb5_cc_select(krb5_context context, krb5_principal server,
princ);
*cache_out = cache;
*princ_out = princ;
- return 0;
+ goto cleanup;
} else if (ret == KRB5_CC_NOTFOUND) {
TRACE_CCSELECT_MODNOTFOUND(context, h->vt.name, server, princ);
*princ_out = princ;
- return ret;
+ goto cleanup;
} else if (ret != KRB5_PLUGIN_NO_HANDLE) {
TRACE_CCSELECT_MODFAIL(context, h->vt.name, ret, server);
- return ret;
+ goto cleanup;
}
}
}
TRACE_CCSELECT_NOTFOUND(context, server);
- return KRB5_CC_NOTFOUND;
+ ret = KRB5_CC_NOTFOUND;
+
+cleanup:
+ krb5_free_principal(context, srvcp);
+ krb5_free_host_realm(context, fbrealms);
+ return ret;
}
void
diff --git a/src/tests/gssapi/t_ccselect.py b/src/tests/gssapi/t_ccselect.py
index 1ea614d30..668a2cc62 100755
--- a/src/tests/gssapi/t_ccselect.py
+++ b/src/tests/gssapi/t_ccselect.py
@@ -31,12 +31,18 @@ r2 = K5Realm(create_user=False, realm='KRBTEST2.COM', portbase=62000,
host1 = 'p:' + r1.host_princ
host2 = 'p:' + r2.host_princ
+foo = 'foo.krbtest.com'
+foo2 = 'foo.krbtest2.com'
-# gsserver specifies the target as a GSS name. The resulting
-# principal will have the host-based type, but the realm won't be
-# known before the client cache is selected (since k5test realms have
-# no domain-realm mapping by default).
-gssserver = 'h:host@' + hostname
+# These strings specify the target as a GSS name. The resulting
+# principal will have the host-based type, with the referral realm
+# (since k5test realms have no domain-realm mapping by default).
+# krb5_cc_select() will use the fallback realm, which is either the
+# uppercased parent domain, or the default realm if the hostname is a
+# single component.
+gssserver = 'h:host@' + foo
+gssserver2 = 'h:host@' + foo2
+gsslocal = 'h:host@localhost'
# refserver specifies the target as a principal in the referral realm.
# The principal won't be treated as a host principal by the
@@ -66,6 +72,16 @@ r1.addprinc(alice, password('alice'))
r1.addprinc(bob, password('bob'))
r2.addprinc(zaphod, password('zaphod'))
+# Create host principals and keytabs for fallback realm tests.
+r1.addprinc('host/localhost')
+r2.addprinc('host/localhost')
+r1.addprinc('host/' + foo)
+r2.addprinc('host/' + foo2)
+r1.extract_keytab('host/localhost', r1.keytab)
+r2.extract_keytab('host/localhost', r2.keytab)
+r1.extract_keytab('host/' + foo, r1.keytab)
+r2.extract_keytab('host/' + foo2, r2.keytab)
+
# Get tickets for one user in each realm (zaphod will be primary).
r1.kinit(alice, password('alice'))
r2.kinit(zaphod, password('zaphod'))
@@ -93,10 +109,24 @@ if output != (zaphod + '\n'):
fail('zaphod not chosen as default initiator name for server in r1')
# Check that primary cache is used if server realm is unknown.
-output = r2.run(['./t_ccselect', gssserver])
+output = r2.run(['./t_ccselect', refserver])
if output != (zaphod + '\n'):
fail('zaphod not chosen via primary cache for unknown server realm')
-r1.run(['./t_ccselect', gssserver], expected_code=1)
+r1.run(['./t_ccselect', gssserver2], expected_code=1)
+# Check ccache selection using a fallback realm.
+output = r1.run(['./t_ccselect', gssserver])
+if output != (alice + '\n'):
+ fail('alice not chosen via parent domain fallback')
+output = r2.run(['./t_ccselect', gssserver2])
+if output != (zaphod + '\n'):
+ fail('zaphod not chosen via parent domain fallback')
+# Check ccache selection using a fallback realm (default realm).
+output = r1.run(['./t_ccselect', gsslocal])
+if output != (alice + '\n'):
+ fail('alice not chosen via default realm fallback')
+output = r2.run(['./t_ccselect', gsslocal])
+if output != (zaphod + '\n'):
+ fail('zaphod not chosen via default realm fallback')
# Get a second cred in r1 (bob will be primary).
r1.kinit(bob, password('bob'))
@@ -104,19 +134,19 @@ r1.kinit(bob, password('bob'))
# Try some cache selections using .k5identity.
k5id = open(os.path.join(r1.testdir, '.k5identity'), 'w')
k5id.write('%s realm=%s\n' % (alice, r1.realm))
-k5id.write('%s service=ho*t host=%s\n' % (zaphod, hostname))
+k5id.write('%s service=ho*t host=localhost\n' % zaphod)
k5id.write('noprinc service=bogus')
k5id.close()
output = r1.run(['./t_ccselect', host1])
if output != (alice + '\n'):
fail('alice not chosen via .k5identity realm line.')
-output = r2.run(['./t_ccselect', gssserver])
+output = r2.run(['./t_ccselect', gsslocal])
if output != (zaphod + '\n'):
fail('zaphod not chosen via .k5identity service/host line.')
output = r1.run(['./t_ccselect', refserver])
if output != (bob + '\n'):
fail('bob not chosen via primary cache when no .k5identity line matches.')
-r1.run(['./t_ccselect', 'h:bogus@' + hostname], expected_code=1,
+r1.run(['./t_ccselect', 'h:bogus@' + foo2], expected_code=1,
expected_msg="Can't find client principal noprinc")
success('GSSAPI credential selection tests')