kdc: Use sname from request rather than user-to-user TGT client name

Assists Samba to address CVE-2020-25719

This may be contary to RFC4120 3.3.3 at
https://datatracker.ietf.org/doc/html/rfc4120/#section-3.3.3
(clearer in the GSS mechanism here:
https://datatracker.ietf.org/doc/html/draft-swift-win2k-krb-user2user-03 )
as server-name is decribed as optional, however Windows AD and Samba
both require that the server-name exist and be a valid SPN matching
the provided TGT.

The lookup of SPN -> entry ensures that the SPN the client thought it
was connecting to was held by the target server. it could be the
typical user principal, or a service principal, but needs to be checked
for the client not to be fooled into connecting to the wrong service.

Samba BUG: https://bugzilla.samba.org/show_bug.cgi?id=14873

Signed-off-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>

(Similar to Samba commit fd50fecbe99ae4fc63843c796d0a516731a1fe6a)
This commit is contained in:
Joseph Sutton
2021-11-16 13:04:44 +13:00
committed by Luke Howard
parent b768c78fca
commit 4112f6fc79

View File

@@ -1429,81 +1429,7 @@ tgs_build_reply(astgs_request_t priv,
if (b->kdc_options.canonicalize)
flags |= HDB_F_CANON;
if(b->kdc_options.enc_tkt_in_skey){
Ticket *t;
hdb_entry_ex *uu;
krb5_principal p;
Key *uukey;
krb5uint32 second_kvno = 0;
krb5uint32 *kvno_ptr = NULL;
if(b->additional_tickets == NULL ||
b->additional_tickets->len == 0){
ret = KRB5KDC_ERR_BADOPTION; /* ? */
kdc_log(context, config, 4,
"No second ticket present in user-to-user request");
_kdc_audit_addreason((kdc_request_t)priv,
"No second ticket present in user-to-user request");
goto out;
}
t = &b->additional_tickets->val[0];
if(!get_krbtgt_realm(&t->sname)){
kdc_log(context, config, 4,
"Additional ticket is not a ticket-granting ticket");
_kdc_audit_addreason((kdc_request_t)priv,
"Additional ticket is not a ticket-granting ticket");
ret = KRB5KDC_ERR_POLICY;
goto out;
}
ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
if (ret)
goto out;
ret = krb5_unparse_name(context, p, &tpn);
if (ret)
goto out;
if(t->enc_part.kvno){
second_kvno = *t->enc_part.kvno;
kvno_ptr = &second_kvno;
}
ret = _kdc_db_fetch(context, config, p,
HDB_F_GET_KRBTGT, kvno_ptr,
NULL, &uu);
krb5_free_principal(context, p);
if(ret){
if (ret == HDB_ERR_NOENTRY)
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user service principal (TGS) unknown");
goto out;
}
ret = hdb_enctype2key(context, &uu->entry, NULL,
t->enc_part.etype, &uukey);
if(ret){
_kdc_free_ent(context, uu);
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user enctype not supported");
goto out;
}
ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
_kdc_free_ent(context, uu);
if(ret) {
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user TGT decrypt failure");
goto out;
}
ret = _kdc_verify_flags(context, config, &adtkt, tpn);
if (ret) {
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user TGT expired or invalid");
goto out;
}
s = &adtkt.cname;
r = adtkt.crealm;
} else if (s == NULL) {
if (s == NULL) {
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
_kdc_set_e_text(priv, "No server in request");
goto out;
@@ -1713,7 +1639,78 @@ server_lookup:
krb5_enctype etype;
if(b->kdc_options.enc_tkt_in_skey) {
Ticket *t;
hdb_entry_ex *uu;
krb5_principal p;
Key *uukey;
krb5uint32 second_kvno = 0;
krb5uint32 *kvno_ptr = NULL;
size_t i;
if(b->additional_tickets == NULL ||
b->additional_tickets->len == 0){
ret = KRB5KDC_ERR_BADOPTION; /* ? */
kdc_log(context, config, 4,
"No second ticket present in user-to-user request");
_kdc_audit_addreason((kdc_request_t)priv,
"No second ticket present in user-to-user request");
goto out;
}
t = &b->additional_tickets->val[0];
if(!get_krbtgt_realm(&t->sname)){
kdc_log(context, config, 4,
"Additional ticket is not a ticket-granting ticket");
_kdc_audit_addreason((kdc_request_t)priv,
"Additional ticket is not a ticket-granting ticket");
ret = KRB5KDC_ERR_POLICY;
goto out;
}
ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
if (ret)
goto out;
ret = krb5_unparse_name(context, p, &tpn);
if (ret)
goto out;
if(t->enc_part.kvno){
second_kvno = *t->enc_part.kvno;
kvno_ptr = &second_kvno;
}
ret = _kdc_db_fetch(context, config, p,
HDB_F_GET_KRBTGT, kvno_ptr,
NULL, &uu);
krb5_free_principal(context, p);
if(ret){
if (ret == HDB_ERR_NOENTRY)
ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user service principal (TGS) unknown");
goto out;
}
ret = hdb_enctype2key(context, &uu->entry, NULL,
t->enc_part.etype, &uukey);
if(ret){
_kdc_free_ent(context, uu);
ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user enctype not supported");
goto out;
}
ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
_kdc_free_ent(context, uu);
if(ret) {
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user TGT decrypt failure");
goto out;
}
ret = _kdc_verify_flags(context, config, &adtkt, tpn);
if (ret) {
_kdc_audit_addreason((kdc_request_t)priv,
"User-to-user TGT expired or invalid");
goto out;
}
ekey = &adtkt.key;
for(i = 0; i < b->etype.len; i++)
if (b->etype.val[i] == adtkt.key.keytype)