2017-06-23 20:45:14 +00:00
|
|
|
From 4963152dc973e8ff74f257f64b0960a7716b480c Mon Sep 17 00:00:00 2001
|
2017-02-17 22:47:37 +00:00
|
|
|
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)
|
|
|
|
---
|
2017-06-23 20:45:14 +00:00
|
|
|
src/lib/krb5/ccache/ccselect.c | 37 ++++++++++++++++++++++++++-----
|
|
|
|
src/tests/gssapi/t_ccselect.py | 50 +++++++++++++++++++++++++++++++++---------
|
|
|
|
2 files changed, 72 insertions(+), 15 deletions(-)
|
2017-02-17 22:47:37 +00:00
|
|
|
|
|
|
|
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
|
2017-06-23 20:45:14 +00:00
|
|
|
index 1ea614d30..668a2cc62 100755
|
2017-02-17 22:47:37 +00:00
|
|
|
--- 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
|
2017-06-23 20:45:14 +00:00
|
|
|
@@ -66,6 +72,16 @@ r1.addprinc(alice, password('alice'))
|
2017-02-17 22:47:37 +00:00
|
|
|
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'))
|
2017-06-23 20:45:14 +00:00
|
|
|
@@ -93,10 +109,24 @@ if output != (zaphod + '\n'):
|
2017-02-17 22:47:37 +00:00
|
|
|
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'))
|
2017-06-23 20:45:14 +00:00
|
|
|
@@ -104,19 +134,19 @@ r1.kinit(bob, password('bob'))
|
2017-02-17 22:47:37 +00:00
|
|
|
# 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.')
|
2017-06-23 20:45:14 +00:00
|
|
|
-r1.run(['./t_ccselect', 'h:bogus@' + hostname], expected_code=1,
|
2017-02-17 22:47:37 +00:00
|
|
|
+r1.run(['./t_ccselect', 'h:bogus@' + foo2], expected_code=1,
|
2017-06-23 20:45:14 +00:00
|
|
|
expected_msg="Can't find client principal noprinc")
|
2017-02-17 22:47:37 +00:00
|
|
|
|
|
|
|
success('GSSAPI credential selection tests')
|