Permalink
Browse files

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)
  • Loading branch information...
mrogers950 authored and greghudson committed Feb 10, 2017
1 parent 17e8864 commit 234b64bd6139d5b75dadd5abbd5bef5a162e298a
Showing with 73 additions and 16 deletions.
  1. +32 −5 src/lib/krb5/ccache/ccselect.c
  2. +41 −11 src/tests/gssapi/t_ccselect.py
@@ -132,14 +132,36 @@ 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;
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
@@ -31,12 +31,18 @@
host1 = 'p:' + r1.host_princ
host2 = 'p:' + r2.host_princ
# 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
foo = 'foo.krbtest.com'
foo2 = 'foo.krbtest2.com'
# 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(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,30 +109,44 @@
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'))
# 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')

0 comments on commit 234b64b

Please sign in to comment.