krb5: decorate PrincipalNameAttrs with krb5_pac

Add krb5_pac to PrincipalNameAttrs to avoid needing to re-parse it each time
gss_get_name_attribute() is called.
This commit is contained in:
Luke Howard
2022-01-07 11:32:28 +11:00
parent 0e8c4ccc6e
commit 5a952ee7b5
5 changed files with 135 additions and 50 deletions

View File

@@ -5,4 +5,5 @@
--sequence=ETYPE-INFO
--sequence=ETYPE-INFO2
--preserve-binary=KDC-REQ-BODY
--decorate=PrincipalNameAttrs:void:pac?:::
--decorate=Principal:PrincipalNameAttrs:nameattrs?

View File

@@ -169,6 +169,7 @@ static get_name_attr_f get_realm;
static get_name_attr_f get_ncomps;
static get_name_attr_f get_peer_realm;
static get_name_attr_f get_pac;
static get_name_attr_f get_pac_buffer;
static get_name_attr_f get_authz_data;
static get_name_attr_f get_ticket_authz_data;
static get_name_attr_f get_authenticator_authz_data;
@@ -210,16 +211,16 @@ static struct krb5_name_attrs {
{ NB("peer-realm"), get_peer_realm, NULL, NULL, 1, 1 },
{ NB("ticket-authz-data#pac"), get_pac, NULL, NULL, 1, 1 },
{ NM(""), get_pac, NULL, NULL, 1, 0 },
{ NM("logon-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("credentials-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("server-checksum"), get_pac, NULL, NULL, 1, 0 },
{ NM("privsvr-checksum"), get_pac, NULL, NULL, 1, 0 },
{ NM("client-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("delegation-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("upn-dns-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("ticket-checksum"), get_pac, NULL, NULL, 1, 0 },
{ NM("attributes-info"), get_pac, NULL, NULL, 1, 0 },
{ NM("requestor-sid"), get_pac, NULL, NULL, 1, 0 },
{ NM("logon-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("credentials-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("server-checksum"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("privsvr-checksum"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("client-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("delegation-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("upn-dns-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("ticket-checksum"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("attributes-info"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NM("requestor-sid"), get_pac_buffer, NULL, NULL, 1, 0 },
{ NB("ticket-authz-data#kdc-issued"),
get_ticket_authz_data, NULL, NULL, 1, 1 },
{ NB("ticket-authz-data"),
@@ -686,29 +687,69 @@ get_pac(OM_uint32 *minor_status,
{
krb5_error_code kret;
krb5_context context;
krb5_data data, pac_data;
krb5_data suffix;
krb5_data data;
PrincipalNameAttrs *nameattrs = name->nameattrs;
PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
EncTicketPart *ticket = NULL;
krb5_data_zero(&data);
krb5_data_zero(&pac_data);
if (src) switch (src->element) {
case choice_PrincipalNameAttrSrc_enc_ticket_part:
ticket = &src->u.enc_ticket_part;
break;
case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
default:
return GSS_S_UNAVAILABLE;
}
if (src == NULL ||
src->element != choice_PrincipalNameAttrSrc_enc_ticket_part)
return GSS_S_UNAVAILABLE;
ticket = &src->u.enc_ticket_part;
if (prefix->length || !authenticated || !ticket)
return GSS_S_UNAVAILABLE;
GSSAPI_KRB5_INIT(&context);
*authenticated = nameattrs->pac_verified;
if (complete)
*complete = 1;
kret = _krb5_get_ad(context, ticket->authorization_data,
NULL, KRB5_AUTHDATA_WIN2K_PAC,
value ? &data : NULL);
if (value) {
value->length = data.length;
value->value = data.data;
}
*minor_status = kret;
if (kret == ENOENT)
return GSS_S_UNAVAILABLE;
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
}
static OM_uint32
get_pac_buffer(OM_uint32 *minor_status,
const CompositePrincipal *name,
gss_const_buffer_t prefix,
gss_const_buffer_t attr,
gss_const_buffer_t frag,
int *authenticated,
int *complete,
gss_buffer_t value,
gss_buffer_t display_value,
int *more)
{
krb5_error_code kret;
krb5_context context;
krb5_data data;
PrincipalNameAttrs *nameattrs = name->nameattrs;
krb5_data suffix;
krb5_data_zero(&data);
if (prefix->length || !authenticated ||
!nameattrs || !nameattrs->pac)
return GSS_S_UNAVAILABLE;
GSSAPI_KRB5_INIT(&context);
if (ATTR_EQ_PREFIX(attr, "urn:mspac:")) {
suffix.length = attr->length - (sizeof("urn:mspac:") - 1);
suffix.data = (char *)attr->value + sizeof("urn:mspac:") - 1;
@@ -716,37 +757,20 @@ get_pac(OM_uint32 *minor_status,
suffix.length = frag->length - sizeof("pac-") - 1;
suffix.data = (char *)frag->value + sizeof("pac-") - 1;
} else
krb5_data_zero(&suffix); /* ticket-authz-data#pac */
return GSS_S_UNAVAILABLE; /* should not be reached */
*authenticated = nameattrs->pac_verified;
if (complete)
*complete = 1;
kret = _krb5_get_ad(context, ticket->authorization_data,
NULL, KRB5_AUTHDATA_WIN2K_PAC, &pac_data);
if (kret == 0 && suffix.length) {
krb5_pac pac;
kret = _krb5_pac_get_buffer_by_name(context, nameattrs->pac, &suffix,
value ? &data : NULL);
kret = krb5_pac_parse(context, pac_data.data, pac_data.length, &pac);
if (kret == 0) {
kret = _krb5_pac_get_buffer_by_name(context, pac, &suffix,
value ? &data : NULL);
krb5_pac_free(context, pac);
}
if (value) {
value->length = data.length;
value->value = data.data;
krb5_data_zero(&data);
}
} else if (kret == 0 && value) {
value->length = pac_data.length;
value->value = pac_data.data;
krb5_data_zero(&pac_data);
if (value) {
value->length = data.length;
value->value = data.data;
}
krb5_data_free(&pac_data);
krb5_data_free(&data);
*minor_status = kret;
if (kret == ENOENT)
return GSS_S_UNAVAILABLE;
@@ -1083,6 +1107,10 @@ get_canonical_name(OM_uint32 *minor_status,
kret = _krb5_principalname2krb5_principal(context, &p,
kdcrep->sname,
kdcrep->srealm);
} else if (nameattrs && nameattrs->pac &&
(_krb5_pac_get_canon_principal(context, nameattrs->pac, &p)) == 0) {
if (authenticated)
*authenticated = nameattrs->pac_verified;
} else if (ticket) {
krb5_data data;
krb5_pac pac = NULL;

View File

@@ -1998,3 +1998,41 @@ _krb5_kdc_pac_sign_ticket(krb5_context context,
krb5_data_free(&rspac);
return ret;
}
/*
* Helper function for krb5_copy_principal(), because the krb5_pac
* in nameattrs lacks a copy constructor (not being an ASN.1 type)
*/
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_pac_copy(krb5_context context, krb5_pac in, krb5_pac *out)
{
krb5_error_code ret;
krb5_pac p;
*out = NULL;
ret = krb5_pac_parse(context, in->data.data, in->data.length, &p);
if (ret == 0 && in->ticket_sign_data.data)
ret = krb5_data_copy(&p->ticket_sign_data, in->ticket_sign_data.data,
in->ticket_sign_data.length);
if (ret == 0 && in->upn_princ)
ret = krb5_copy_principal(context, in->upn_princ, &p->upn_princ);
p->upn_flags = in->upn_flags;
if (ret == 0 && in->canon_princ)
ret = krb5_copy_principal(context, in->canon_princ, &p->canon_princ);
if (ret == 0 && in->sid.data)
ret = krb5_data_copy(&p->sid, in->sid.data, in->sid.length);
p->pac_attributes = in->pac_attributes;
if (ret) {
krb5_pac_free(context, p);
return ret;
}
*out = p;
return 0;
}

View File

@@ -102,10 +102,13 @@ KRB5_LIB_FUNCTION void KRB5_LIB_CALL
krb5_free_principal(krb5_context context,
krb5_principal p)
{
if(p){
free_Principal(p);
free(p);
}
if (p == NULL)
return;
if (p->nameattrs)
krb5_pac_free(context, p->nameattrs->pac);
free_Principal(p);
free(p);
}
/**
@@ -926,12 +929,25 @@ krb5_copy_principal(krb5_context context,
krb5_principal *outprinc)
{
krb5_principal p = malloc(sizeof(*p));
krb5_error_code ret;
if (p == NULL)
return krb5_enomem(context);
if(copy_Principal(inprinc, p)) {
free(p);
return krb5_enomem(context);
}
if (inprinc->nameattrs && inprinc->nameattrs->pac) {
krb5_pac pac;
ret = _krb5_pac_copy(context, inprinc->nameattrs->pac, &pac);
if (ret) {
krb5_free_principal(context, p);
return ret;
}
heim_assert(p->nameattrs, "nameattrs uninitialized");
p->nameattrs->pac = pac;
}
*outprinc = p;
return 0;
}

View File

@@ -1080,9 +1080,11 @@ krb5_rd_req_ctx(krb5_context context,
} else if (ret2 != ENOENT)
ret = ret2;
}
krb5_pac_free(context, pac);
if (ret)
if (ret) {
krb5_pac_free(context, pac);
goto out;
}
o->ticket->client->nameattrs->pac = pac;
} else
ret = 0;
}