diff --git a/lib/asn1/krb5.opt b/lib/asn1/krb5.opt index 3078d7284..29fc22482 100644 --- a/lib/asn1/krb5.opt +++ b/lib/asn1/krb5.opt @@ -5,4 +5,5 @@ --sequence=ETYPE-INFO --sequence=ETYPE-INFO2 --preserve-binary=KDC-REQ-BODY +--decorate=PrincipalNameAttrs:void:pac?::: --decorate=Principal:PrincipalNameAttrs:nameattrs? diff --git a/lib/gssapi/krb5/name_attrs.c b/lib/gssapi/krb5/name_attrs.c index ff1ee5db3..acf044eac 100644 --- a/lib/gssapi/krb5/name_attrs.c +++ b/lib/gssapi/krb5/name_attrs.c @@ -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; diff --git a/lib/krb5/pac.c b/lib/krb5/pac.c index 7c01fe3ba..bfb15a686 100644 --- a/lib/krb5/pac.c +++ b/lib/krb5/pac.c @@ -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; +} diff --git a/lib/krb5/principal.c b/lib/krb5/principal.c index dc6692ff2..9dfeba02f 100644 --- a/lib/krb5/principal.c +++ b/lib/krb5/principal.c @@ -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; } diff --git a/lib/krb5/rd_req.c b/lib/krb5/rd_req.c index fcbfbfa79..84c18e3f5 100644 --- a/lib/krb5/rd_req.c +++ b/lib/krb5/rd_req.c @@ -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; }