Implement hierarchical referrals

This commit is contained in:
Viktor Dukhovni
2016-08-08 14:16:23 -05:00
committed by Nicolas Williams
parent 1501740952
commit 4b4036c9a6
3 changed files with 173 additions and 70 deletions

View File

@@ -1092,23 +1092,6 @@ out:
return ret;
}
/*
*
*/
static const char *
find_rpath(krb5_context context, Realm crealm, Realm srealm)
{
const char *new_realm = krb5_config_get_string(context,
NULL,
"capaths",
crealm,
srealm,
NULL);
return new_realm;
}
static krb5_boolean
need_referral(krb5_context context, krb5_kdc_configuration *config,
const KDCOptions * const options, krb5_principal server,
@@ -1538,6 +1521,12 @@ tgs_build_reply(krb5_context context,
krb5_keyblock sessionkey;
krb5_kvno kvno;
krb5_data rspac;
const char *tgt_realm = /* Realm of TGT issuer */
krb5_principal_get_realm(context, krbtgt->entry.principal);
const char *our_realm = /* Realm of this KDC */
krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
char **capath = NULL;
size_t num_capath = 0;
hdb_entry_ex *krbtgt_out = NULL;
@@ -1545,7 +1534,6 @@ tgs_build_reply(krb5_context context,
PrincipalName *s;
Realm r;
int nloop = 0;
EncTicketPart adtkt;
char opt_str[128];
int signedpath = 0;
@@ -1654,11 +1642,10 @@ server_lookup:
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
goto out;
} else if (ret == HDB_ERR_WRONG_REALM) {
if (ref_realm)
free(ref_realm);
ref_realm = strdup(server->entry.principal->realm);
if (ref_realm == NULL) {
ret = ENOMEM;
ret = krb5_enomem(context);
goto out;
}
@@ -1668,12 +1655,12 @@ server_lookup:
ref_realm, spn);
krb5_free_principal(context, sp);
sp = NULL;
free(spn);
spn = NULL;
ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
ref_realm, NULL);
if (ret)
goto out;
free(spn);
spn = NULL;
ret = krb5_unparse_name(context, sp, &spn);
if (ret)
goto out;
@@ -1685,26 +1672,36 @@ server_lookup:
krb5_realm *realms;
if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
if (nloop++ < 2) {
new_rlm = find_rpath(context, tgt->crealm, req_rlm);
if(new_rlm) {
kdc_log(context, config, 5, "krbtgt for realm %s "
"not found, trying %s",
req_rlm, new_rlm);
if (capath == NULL) {
ret = _krb5_find_capath(context, tgt->crealm, our_realm,
req_rlm, TRUE, &capath, &num_capath);
if (ret)
goto out;
}
new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
if (new_rlm) {
kdc_log(context, config, 5, "krbtgt from %s via %s for "
"realm %s not found, trying %s", tgt->crealm,
our_realm, req_rlm, new_rlm);
free(ref_realm);
ref_realm = strdup(new_rlm);
if (ref_realm == NULL) {
ret = krb5_enomem(context);
goto out;
}
krb5_free_principal(context, sp);
free(spn);
sp = NULL;
krb5_make_principal(context, &sp, r,
KRB5_TGS_NAME, new_rlm, NULL);
KRB5_TGS_NAME, ref_realm, NULL);
free(spn);
spn = NULL;
ret = krb5_unparse_name(context, sp, &spn);
if (ret)
goto out;
if (ref_realm)
free(ref_realm);
ref_realm = strdup(new_rlm);
goto server_lookup;
}
}
} else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
if (strcmp(realms[0], sp->realm) != 0) {
kdc_log(context, config, 5,
@@ -1712,16 +1709,17 @@ server_lookup:
"server %s that was not found",
realms[0], spn);
krb5_free_principal(context, sp);
free(spn);
sp = NULL;
krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
realms[0], NULL);
free(spn);
spn = NULL;
ret = krb5_unparse_name(context, sp, &spn);
if (ret) {
krb5_free_host_realm(context, realms);
goto out;
}
if (ref_realm)
free(ref_realm);
ref_realm = strdup(realms[0]);
@@ -1827,17 +1825,13 @@ server_lookup:
* have been an incoming trust)
*/
{
const char *remote_realm =
krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
ret = krb5_make_principal(context,
&krbtgt_out_principal,
remote_realm,
our_realm,
KRB5_TGS_NAME,
remote_realm,
our_realm,
NULL);
if(ret) {
if (ret) {
kdc_log(context, config, 0,
"Failed to make krbtgt principal name object for "
"authz-data signatures");
@@ -1850,7 +1844,6 @@ server_lookup:
"authz-data signatures");
goto out;
}
}
ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
@@ -2349,6 +2342,7 @@ out:
free(cpn);
free(dpn);
free(krbtgt_out_n);
_krb5_free_capath(context, capath);
krb5_data_free(&rspac);
krb5_free_keyblock_contents(context, &sessionkey);
@@ -2367,7 +2361,6 @@ out:
krb5_free_principal(context, dp);
krb5_free_principal(context, sp);
krb5_free_principal(context, krbtgt_out_principal);
if (ref_realm)
free(ref_realm);
free_METHOD_DATA(&enc_pa_data);

View File

@@ -54,6 +54,17 @@ R5=SOME-REALM5.FR
R6=SOME-REALM6.US
R7=SOME-REALM7.UK
H1=H1.$R
H2=H2.$R
H3=H3.$H2
H4=H4.$H2
r=`echo "$R" | tr '[A-Z]' '[a-z]'`
h1=`echo "${H1}" | tr '[A-Z]' '[a-z]'`
h2=`echo "${H2}" | tr '[A-Z]' '[a-z]'`
h3=`echo "${H3}" | tr '[A-Z]' '[a-z]'`
h4=`echo "${H4}" | tr '[A-Z]' '[a-z]'`
port=@port@
pwport=@pwport@
@@ -137,6 +148,30 @@ ${kadmin} \
--realm-max-renewable-life=1month \
${R7} || exit 1
${kadmin} \
init \
--realm-max-ticket-life=1day \
--realm-max-renewable-life=1month \
${H1} || exit 1
${kadmin} \
init \
--realm-max-ticket-life=1day \
--realm-max-renewable-life=1month \
${H2} || exit 1
${kadmin} \
init \
--realm-max-ticket-life=1day \
--realm-max-renewable-life=1month \
${H3} || exit 1
${kadmin} \
init \
--realm-max-ticket-life=1day \
--realm-max-renewable-life=1month \
${H4} || exit 1
${kadmin} \
init \
--realm-max-ticket-life=1day \
@@ -149,12 +184,21 @@ ${kadmin} cpw -r krbtgt/${R}@${R} || exit 1
${kadmin} cpw -r krbtgt/${R}@${R} || exit 1
${kadmin} add -p foo --use-defaults foo@${R} || exit 1
${kadmin} add -p foo --use-defaults foo/host.${r}@${R} || exit 1
${kadmin} add -p foo --use-defaults foo@${R2} || exit 1
${kadmin} add -p foo --use-defaults foo@${R3} || exit 1
${kadmin} add -p foo --use-defaults foo@${R4} || exit 1
${kadmin5} add -p foo --use-defaults foo@${R5} || exit 1
${kadmin} add -p foo --use-defaults foo@${R6} || exit 1
${kadmin} add -p foo --use-defaults foo@${R7} || exit 1
${kadmin} add -p foo --use-defaults foo@${H1} || exit 1
${kadmin} add -p foo --use-defaults foo/host.${h1}@${H1} || exit 1
${kadmin} add -p foo --use-defaults foo@${H2} || exit 1
${kadmin} add -p foo --use-defaults foo/host.${h2}@${H2} || exit 1
${kadmin} add -p foo --use-defaults foo@${H3} || exit 1
${kadmin} add -p foo --use-defaults foo/host.${h3}@${H3} || exit 1
${kadmin} add -p foo --use-defaults foo@${H4} || exit 1
${kadmin} add -p foo --use-defaults foo/host.${h4}@${H4} || exit 1
${kadmin} add -p bar --use-defaults bar@${R} || exit 1
${kadmin} add -p foo --use-defaults remove@${R} || exit 1
${kadmin} add -p nop --use-defaults ${server}@${R} || exit 1
@@ -205,6 +249,18 @@ ${kadmin} add -p cross2 --use-defaults krbtgt/${R5}@${R6} || exit 1
${kadmin} add -p cross1 --use-defaults krbtgt/${R7}@${R6} || exit 1
${kadmin} add -p cross2 --use-defaults krbtgt/${R6}@${R7} || exit 1
${kadmin} add -p cross1 --use-defaults krbtgt/${H1}@${R} || exit 1
${kadmin} add -p cross2 --use-defaults krbtgt/${R}@${H1} || exit 1
${kadmin} add -p cross1 --use-defaults krbtgt/${H2}@${R} || exit 1
${kadmin} add -p cross2 --use-defaults krbtgt/${R}@${H2} || exit 1
${kadmin} add -p cross1 --use-defaults krbtgt/${H3}@${H2} || exit 1
${kadmin} add -p cross2 --use-defaults krbtgt/${H2}@${H3} || exit 1
${kadmin} add -p cross1 --use-defaults krbtgt/${H3}@${H4} || exit 1
${kadmin} add -p cross2 --use-defaults krbtgt/${H4}@${H3} || exit 1
${kadmin} add -p foo --use-defaults pw-expire@${R} || exit 1
${kadmin} modify --pw-expiration-time=+1day pw-expire@${R} || exit 1
@@ -228,6 +284,10 @@ ${kadmin} check ${R4} || exit 1
${kadmin5} check ${R5} || exit 1
${kadmin} check ${R6} || exit 1
${kadmin} check ${R7} || exit 1
${kadmin} check ${H1} || exit 1
${kadmin} check ${H2} || exit 1
${kadmin} check ${H3} || exit 1
${kadmin} check ${H4} || exit 1
echo "Extracting enctypes"
${ktutil} -k ${keytab} list > tempfile || exit 1
@@ -354,6 +414,30 @@ echo "Getting x-realm tickets with capaths for $R -> $R5"
${kgetcred} foo@${R5} || { ec=1 ; eval "${testfailed}"; }
${kdestroy}
echo "Testing hierarchical referral logic"
${kinit} --password-file=${objdir}/foopassword \
-e ${aesenctype} -e ${aesenctype} \
foo@${H3} || \
{ ec=1 ; eval "${testfailed}"; }
echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $H1"
${kgetcred} --hostbased --canonicalize foo host.${h1} || { ec=1 ; eval "${testfailed}"; }
echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $R"
${kgetcred} --hostbased --canonicalize foo host.${r} || { ec=1 ; eval "${testfailed}"; }
echo "Getting x-realm tickets with hierarchical referrals for $H3 -> $H2"
${kgetcred} --hostbased --canonicalize foo host.${h2} || { ec=1 ; eval "${testfailed}"; }
${kdestroy}
echo "Testing multi-hop [capaths] referral logic"
${kinit} --password-file=${objdir}/foopassword \
-e ${aesenctype} -e ${aesenctype} \
foo@${H4} || \
{ ec=1 ; eval "${testfailed}"; }
echo "Getting x-realm tickets with [capaths] referrals for $H4 -> $H1"
${kgetcred} --hostbased --canonicalize foo/host.${h1}@${H4} || { ec=1 ; eval "${testfailed}"; }
${kdestroy}
echo "Testing forwardable/renewable flag copying in TGS-REQ"
${kinit} -f --renewable -r 5d --password-file=${objdir}/foopassword foo@$R || \
{ ec=1 ; eval "${testfailed}"; }

View File

@@ -43,10 +43,26 @@
TEST-HTTP.H5L.SE = {
kdc = http/localhost:@port@
}
H1.TEST.H5L.SE = {
kdc = localhost:@port@
}
H2.TEST.H5L.SE = {
kdc = localhost:@port@
}
H3.H2.TEST.H5L.SE = {
kdc = localhost:@port@
}
H4.H2.TEST.H5L.SE = {
kdc = localhost:@port@
}
[domain_realm]
.test.h5l.se = TEST.H5L.SE
.sub.test.h5l.se = SUB.TEST.H5L.SE
.h1.test.h5l.se = H1.TEST.H5L.SE
.h2.test.h5l.se = H2.TEST.H5L.SE
.h3.h2.test.h5l.se = H3.H2.TEST.H5L.SE
.h4.h2.test.h5l.se = H4.H2.TEST.H5L.SE
.example.com = TEST2.H5L.SE
localhost = TEST.H5L.SE
.localdomain = TEST.H5L.SE
@@ -131,3 +147,13 @@
SOME-REALM7.UK = SOME-REALM6.US
SOME-REALM7.UK = SOME-REALM5.FR
}
H4.H2.TEST.H5L.SE = {
H1.TEST.H5L.SE = H3.H2.TEST.H5L.SE
H1.TEST.H5L.SE = H2.TEST.H5L.SE
H1.TEST.H5L.SE = TEST.H5L.SE
TEST.H5L.SE = H3.H2.TEST.H5L.SE
TEST.H5L.SE = H2.TEST.H5L.SE
H2.TEST.H5L.SE = H3.H2.TEST.H5L.SE
}