gsskrb5: Add simple name attributes support
This adds Kerberos mechanism support for: - composite principal name export/import - getting rudimentary name attributes from GSS names using gss_get_name_attribute(): - all (raw) authorization data from the Ticket - all (raw) authorization data from the Authenticator - transit path - realm - component count - each component - gss_inquire_name() - gss_display_name_ext() (just for the hostbased service name type though) The test exercises almost all of the functionality, except for: - getting the PAC - getting authz-data from the Authenticator - getting the transit path TBD (much) later: - amend test_context to do minimal name attribute checks as well - gss_set_name_attribute() (to request authz-data) - gss_delete_name_attribute() - getting specific authorization data elements via URN fragments (as opposed to all of them) - parsing the PAC, extracting SIDs (each one as a separate value) - some configurable local policy (?) - plugin interface for additional local policy
This commit is contained in:

committed by
Nico Williams

parent
1cede09a0b
commit
be708ca3cf
@@ -152,6 +152,13 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_export_name_oid_desc =
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_nt_principal_name_oid_desc =
|
||||
{10, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01") };
|
||||
|
||||
/*
|
||||
* GSS_C_NT_COMPOSITE_EXPORT [RFC6680], OID {iso(1) identified-organization(3)
|
||||
* dod(6) internet(1) security(5) nametypes(6) gss-composite-export(6)}.
|
||||
*/
|
||||
gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_nt_composite_export_oid_desc =
|
||||
{6, rk_UNCONST("\x2b\x06\x01\x05\x06\x06")};
|
||||
|
||||
/*
|
||||
* draft-ietf-cat-iakerb-09, IAKERB:
|
||||
* The mechanism ID for IAKERB proxy GSS-API Kerberos, in accordance
|
||||
@@ -383,12 +390,12 @@ static gssapi_mech_interface_desc krb5_mech = {
|
||||
sizeof(krb5_mo) / sizeof(krb5_mo[0]),
|
||||
_gsskrb5_localname,
|
||||
_gsskrb5_authorize_localname,
|
||||
NULL, /* gm_display_name_ext */
|
||||
NULL, /* gm_inquire_name */
|
||||
NULL, /* gm_get_name_attribute */
|
||||
_gsskrb5_display_name_ext,
|
||||
_gsskrb5_inquire_name,
|
||||
_gsskrb5_get_name_attribute,
|
||||
NULL, /* gm_set_name_attribute */
|
||||
NULL, /* gm_delete_name_attribute */
|
||||
NULL, /* gm_export_name_composite */
|
||||
_gsskrb5_export_name_composite,
|
||||
_gsskrb5_duplicate_cred,
|
||||
_gsskrb5_add_cred_from,
|
||||
_gsskrb5_store_cred_into,
|
||||
|
@@ -169,9 +169,11 @@ import_export_name (OM_uint32 *minor_status,
|
||||
const gss_buffer_t input_name_buffer,
|
||||
gss_name_t *output_name)
|
||||
{
|
||||
CompositePrincipal *composite;
|
||||
unsigned char *p;
|
||||
uint32_t length;
|
||||
size_t length, sz;
|
||||
OM_uint32 ret;
|
||||
int is_composite;
|
||||
char *name;
|
||||
|
||||
if (input_name_buffer->length < 10 + GSS_KRB5_MECHANISM->length)
|
||||
@@ -181,7 +183,9 @@ import_export_name (OM_uint32 *minor_status,
|
||||
|
||||
p = input_name_buffer->value;
|
||||
|
||||
if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
|
||||
if (p[0] != 0x04 ||
|
||||
(p[1] != 0x01 && p[1] != 0x02) ||
|
||||
p[2] != 0x00 ||
|
||||
p[3] != GSS_KRB5_MECHANISM->length + 2 ||
|
||||
p[4] != 0x06 ||
|
||||
p[5] != GSS_KRB5_MECHANISM->length ||
|
||||
@@ -189,6 +193,8 @@ import_export_name (OM_uint32 *minor_status,
|
||||
GSS_KRB5_MECHANISM->length) != 0)
|
||||
return GSS_S_BAD_NAME;
|
||||
|
||||
is_composite = p[1] == 0x02;
|
||||
|
||||
p += 6 + GSS_KRB5_MECHANISM->length;
|
||||
|
||||
length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
|
||||
@@ -197,6 +203,28 @@ import_export_name (OM_uint32 *minor_status,
|
||||
if (length > input_name_buffer->length - 10 - GSS_KRB5_MECHANISM->length)
|
||||
return GSS_S_BAD_NAME;
|
||||
|
||||
if (is_composite) {
|
||||
if ((composite = calloc(1, sizeof(*composite))) == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
ret = decode_CompositePrincipal(p, length, composite, &sz);
|
||||
if (ret) {
|
||||
*minor_status = ret;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
if (sz != length) {
|
||||
free_CompositePrincipal(composite);
|
||||
free(composite);
|
||||
*minor_status = EINVAL;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
*output_name = (void *)composite;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
|
||||
name = malloc(length + 1);
|
||||
if (name == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
@@ -207,7 +235,6 @@ import_export_name (OM_uint32 *minor_status,
|
||||
|
||||
ret = parse_krb5_name(minor_status, context, name, output_name);
|
||||
free(name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -239,7 +266,8 @@ OM_uint32 GSSAPI_CALLCONV _gsskrb5_import_name
|
||||
context,
|
||||
input_name_buffer,
|
||||
output_name);
|
||||
else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
|
||||
else if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME) ||
|
||||
gss_oid_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT)) {
|
||||
return import_export_name(minor_status,
|
||||
context,
|
||||
input_name_buffer,
|
||||
|
692
lib/gssapi/krb5/name_attrs.c
Normal file
692
lib/gssapi/krb5/name_attrs.c
Normal file
@@ -0,0 +1,692 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "gsskrb5_locl.h"
|
||||
|
||||
/*
|
||||
* (Not-yet-)Standard name attributes for Kerberos MNs,
|
||||
* GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "...".
|
||||
*
|
||||
* I.e., "urn:ietf:kerberos:nameattr-...". (XXX Register this URN namespace
|
||||
* with IANA.)
|
||||
*
|
||||
* Note that we do use URN fragments.
|
||||
*
|
||||
* Specific attributes below the base URN:
|
||||
*
|
||||
* - name access attributes:
|
||||
* - "realm" -> realm of name
|
||||
* - "name-ncomp" -> count of name components
|
||||
* - "name-ncomp#<digit>" -> name component N (0 <= N <= 9)
|
||||
*
|
||||
* Ticket and Authenticator access attributes:
|
||||
*
|
||||
* - "transit-path" -> encoding of the transited path
|
||||
* - "authenticator-authz-data" -> encoding of all of the authz-data from
|
||||
* the AP-REQ's Authenticator
|
||||
* - "ticket-authz-data" -> encoding of all of the authz-data from
|
||||
* the AP-REQ's Ticket
|
||||
* - "ticket-authz-data#pac" -> the PAC
|
||||
* - "authz-data#<N>" -> encoding of all of a specific auth-data
|
||||
* element type N (e.g., 2, meaning
|
||||
* AD-INTENDED-FOR-SERVER)
|
||||
*
|
||||
* Misc. attributes:
|
||||
*
|
||||
* - "peer-realm" -> name of peer's realm (if this is an MN
|
||||
* resulting for establishing a security
|
||||
* context)
|
||||
* - "canonical-name" -> exported name token and RFC1964 display
|
||||
* syntax of the name's canonical name
|
||||
*
|
||||
* Compatibility with MIT:
|
||||
*
|
||||
* - "urn:mspac:" -> the PAC
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
* - Add some sort of display syntax for transit path
|
||||
* - Add support for URN q-components or attribute prefixes to specify
|
||||
* alternative raw and/or display value encodings (JSON?)
|
||||
* - Add support for attributes for accessing other parts of the Ticket / KDC
|
||||
* reply enc-parts, like auth times
|
||||
* - Add support for getting specific PAC buffers
|
||||
* - Add support for getting PAC login fields, including SIDs (one at a time)
|
||||
* - Add support for CAMMAC?
|
||||
*/
|
||||
|
||||
static int
|
||||
attr_eq(gss_buffer_t attr, const char *aname, size_t aname_len)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if (attr->length < aname_len)
|
||||
return 0;
|
||||
/* Note: `s' is not NUL-terminated */
|
||||
s = ((const char *)attr->value) + attr->length - aname_len;
|
||||
return strncmp(s, aname, aname_len) == 0 &&
|
||||
(attr->length == aname_len || s[aname_len] == '#');
|
||||
}
|
||||
|
||||
#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1))
|
||||
|
||||
/* Split attribute into prefix, suffix, and fragment. See RFC6680. */
|
||||
static void
|
||||
split_attr(restrict gss_const_buffer_t orig,
|
||||
restrict gss_buffer_t prefix,
|
||||
restrict gss_buffer_t attr,
|
||||
restrict gss_buffer_t frag,
|
||||
int *is_urn)
|
||||
{
|
||||
char *last = NULL;
|
||||
char *p = orig->value;
|
||||
|
||||
*attr = *orig;
|
||||
prefix->value = orig->value;
|
||||
prefix->length = 0;
|
||||
frag->length = 0;
|
||||
frag->value = NULL;
|
||||
|
||||
/* FIXME We don't have a memrchr() in lib/roken */
|
||||
for (p = memchr(p, ' ', orig->length);
|
||||
p;
|
||||
p = p ? memchr(p + 1, ' ', orig->length) : NULL) {
|
||||
last = p;
|
||||
prefix->length = last - (const char *)orig->value;
|
||||
attr->value = last + 1;
|
||||
attr->length = orig->length - (prefix->length + 1);
|
||||
}
|
||||
if (prefix->length == 0)
|
||||
prefix->value = NULL;
|
||||
|
||||
if ((*is_urn = (strncmp(attr->value, "urn:", sizeof("urn:") - 1) == 0)) &&
|
||||
(p = memchr((char *)attr->value + 1, '#', attr->length - 1))) {
|
||||
frag->value = ++p;
|
||||
frag->length = attr->length - (p - (const char *)attr->value);
|
||||
attr->length = --p - (const char *)attr->value;
|
||||
}
|
||||
}
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV
|
||||
_gsskrb5_get_name_attribute(OM_uint32 *minor_status,
|
||||
gss_name_t gname,
|
||||
gss_buffer_t original_attr,
|
||||
int *authenticated,
|
||||
int *complete,
|
||||
gss_buffer_t value,
|
||||
gss_buffer_t display_value,
|
||||
int *more)
|
||||
{
|
||||
krb5_const_principal name = (krb5_const_principal)gname;
|
||||
krb5_error_code kret = 0;
|
||||
gss_buffer_desc prefix, attr, frag;
|
||||
PrincipalNameAttrs *nameattrs = name->nameattrs;
|
||||
PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
|
||||
EncTicketPart *ticket = NULL;
|
||||
EncKDCRepPart *kdcrep = NULL;
|
||||
int is_urn;
|
||||
|
||||
if (src) switch (src->element) {
|
||||
case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
|
||||
kdcrep = &src->u.enc_kdc_rep_part;
|
||||
break;
|
||||
case choice_PrincipalNameAttrSrc_enc_ticket_part:
|
||||
ticket = &src->u.enc_ticket_part;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*minor_status = 0;
|
||||
if (authenticated)
|
||||
*authenticated = 0;
|
||||
if (complete)
|
||||
*complete = 0;
|
||||
if (more)
|
||||
*more = 0;
|
||||
if (value) {
|
||||
value->length = 0;
|
||||
value->value = NULL;
|
||||
}
|
||||
if (display_value) {
|
||||
display_value->length = 0;
|
||||
display_value->value = NULL;
|
||||
}
|
||||
|
||||
split_attr(original_attr, &prefix, &attr, &frag, &is_urn);
|
||||
if (prefix.length || !is_urn)
|
||||
return GSS_S_UNAVAILABLE;
|
||||
|
||||
if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "realm")) {
|
||||
/*
|
||||
* Output the principal's realm. The value and display value are the
|
||||
* same in this case.
|
||||
*/
|
||||
if (authenticated && nameattrs && nameattrs->authenticated)
|
||||
*authenticated = 1;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
if (value) {
|
||||
if ((value->value = strdup(name->realm)) == NULL)
|
||||
goto enomem;
|
||||
value->length = strlen(value->value);
|
||||
}
|
||||
if (display_value) {
|
||||
if ((display_value->value = strdup(name->realm)) == NULL)
|
||||
goto enomem;
|
||||
display_value->length = strlen(display_value->value);
|
||||
}
|
||||
return GSS_S_COMPLETE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "peer-realm") &&
|
||||
nameattrs && nameattrs->peer_realm) {
|
||||
/*
|
||||
* Output the peer's realm. The value and display value are the
|
||||
* same in this case.
|
||||
*/
|
||||
if (authenticated)
|
||||
*authenticated = 1;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
if (value) {
|
||||
if ((value->value = strdup(nameattrs->peer_realm[0])) == NULL)
|
||||
goto enomem;
|
||||
value->length = strlen(value->value);
|
||||
}
|
||||
if (display_value) {
|
||||
if ((display_value->value =
|
||||
strdup(nameattrs->peer_realm[0])) == NULL)
|
||||
goto enomem;
|
||||
display_value->length = strlen(display_value->value);
|
||||
}
|
||||
return GSS_S_COMPLETE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "name-ncomp")) {
|
||||
unsigned char n;
|
||||
|
||||
if (authenticated && nameattrs && nameattrs->authenticated)
|
||||
*authenticated = 1;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
if (frag.length == 0) {
|
||||
if (value) {
|
||||
if ((value->value = malloc(sizeof(size_t))) == NULL)
|
||||
goto enomem;
|
||||
*((size_t *)value->value) = name->name.name_string.len;
|
||||
value->length = sizeof(size_t);
|
||||
}
|
||||
if (display_value) {
|
||||
char *s = NULL;
|
||||
|
||||
if (asprintf(&s, "%u",
|
||||
(unsigned int)name->name.name_string.len) == -1 ||
|
||||
s == NULL)
|
||||
goto enomem;
|
||||
display_value->value = s;
|
||||
display_value->length = strlen(display_value->value);
|
||||
}
|
||||
return GSS_S_COMPLETE;
|
||||
} /* else caller wants a component */
|
||||
if (frag.length != 1 ||
|
||||
((const char *)frag.value)[0] < '0' ||
|
||||
((const char *)frag.value)[0] > '9') {
|
||||
*minor_status = EINVAL;
|
||||
return GSS_S_UNAVAILABLE;
|
||||
}
|
||||
n = ((const char *)frag.value)[0] - '0';
|
||||
if (n >= name->name.name_string.len) {
|
||||
*minor_status = EINVAL;
|
||||
return GSS_S_UNAVAILABLE;
|
||||
}
|
||||
/* The value and the display value are the same in this case */
|
||||
if (value) {
|
||||
if ((value->value = strdup(name->name.name_string.val[n])) == NULL)
|
||||
goto enomem;
|
||||
value->length = strlen(name->name.name_string.val[n]);
|
||||
}
|
||||
if (display_value) {
|
||||
if ((display_value->value =
|
||||
strdup(name->name.name_string.val[n])) == NULL)
|
||||
goto enomem;
|
||||
if (display_value)
|
||||
display_value->length = strlen(name->name.name_string.val[n]);
|
||||
}
|
||||
return GSS_S_COMPLETE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"canonical-name") && src) {
|
||||
krb5_principal p = NULL;
|
||||
krb5_context context;
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = 1;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
if (kdcrep) {
|
||||
kret = _krb5_principalname2krb5_principal(context, &p,
|
||||
kdcrep->sname,
|
||||
kdcrep->srealm);
|
||||
} else if (ticket) {
|
||||
kret = _krb5_principalname2krb5_principal(context, &p,
|
||||
ticket->cname,
|
||||
ticket->crealm);
|
||||
} else
|
||||
return GSS_S_UNAVAILABLE;
|
||||
if (kret == 0 && value) {
|
||||
OM_uint32 major;
|
||||
/*
|
||||
* Value is exported name token (exported composite name token
|
||||
* should also work).
|
||||
*/
|
||||
major = _gsskrb5_export_name(minor_status, (gss_name_t)p, value);
|
||||
if (major != GSS_S_COMPLETE) {
|
||||
krb5_free_principal(context, p);
|
||||
return major;
|
||||
}
|
||||
}
|
||||
if (kret == 0 && display_value) {
|
||||
/* Display value is principal name display form */
|
||||
kret = krb5_unparse_name(context, p,
|
||||
(char **)&display_value->value);
|
||||
if (kret == 0)
|
||||
display_value->length = strlen(display_value->value);
|
||||
}
|
||||
|
||||
krb5_free_principal(context, p);
|
||||
if (kret) {
|
||||
if (value) {
|
||||
free(value->value);
|
||||
value->length = 0;
|
||||
value->value = NULL;
|
||||
}
|
||||
*minor_status = kret;
|
||||
return GSS_S_UNAVAILABLE;
|
||||
}
|
||||
return GSS_S_COMPLETE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "authz-data") &&
|
||||
frag.length &&
|
||||
((nameattrs && nameattrs->authenticator_ad) ||
|
||||
(ticket && ticket->authorization_data))) {
|
||||
krb5_context context;
|
||||
krb5_data data;
|
||||
char *s, *end;
|
||||
int64_t n;
|
||||
|
||||
/* Output a specific AD element from the ticket or authenticator */
|
||||
if ((s = strndup(frag.value, frag.length)) == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
errno = 0;
|
||||
n = strtoll(s, &end, 10);
|
||||
free(s);
|
||||
if (end[0] == '\0' && (errno || n > INT_MAX || n < INT_MIN)) {
|
||||
*minor_status = ERANGE;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
if (end[0] != '\0') {
|
||||
*minor_status = EINVAL;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = 0;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
kret = ENOENT;
|
||||
if (ticket->authorization_data) {
|
||||
kret = _krb5_get_ad(context, ticket->authorization_data,
|
||||
NULL, n, value ? &data : NULL);
|
||||
|
||||
/* If it's from the ticket, it may be authenticated: */
|
||||
if (kret == 0 && authenticated) {
|
||||
if (n == KRB5_AUTHDATA_KDC_ISSUED)
|
||||
*authenticated = nameattrs->kdc_issued_verified;
|
||||
else if (n == KRB5_AUTHDATA_WIN2K_PAC)
|
||||
*authenticated = nameattrs->pac_verified;
|
||||
}
|
||||
}
|
||||
if (kret == ENOENT && nameattrs->authenticator_ad &&
|
||||
n != KRB5_AUTHDATA_KDC_ISSUED &&
|
||||
n != KRB5_AUTHDATA_WIN2K_PAC) {
|
||||
kret = _krb5_get_ad(context, ticket->authorization_data,
|
||||
NULL, n, 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;
|
||||
} else if ((ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"ticket-authz-data#pac") ||
|
||||
ATTR_EQ(&attr, "urn:mspac:")) &&
|
||||
ticket && ticket->authorization_data) {
|
||||
krb5_context context;
|
||||
krb5_data data;
|
||||
|
||||
/*
|
||||
* In MIT the attribute for the whole PAC is "urn:mspac:".
|
||||
*
|
||||
* TBD: Add support for attributes for specific PAC buffers, like MIT.
|
||||
*/
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
if (authenticated)
|
||||
*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;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"ticket-authz-data#kdc-issued") &&
|
||||
ticket &&
|
||||
ticket->authorization_data) {
|
||||
krb5_context context;
|
||||
krb5_data data;
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = nameattrs->kdc_issued_verified;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
kret = _krb5_get_ad(context, ticket->authorization_data,
|
||||
NULL, KRB5_AUTHDATA_KDC_ISSUED,
|
||||
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;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"ticket-authz-data") &&
|
||||
frag.length == 0 && ticket && ticket->authorization_data) {
|
||||
size_t sz;
|
||||
|
||||
/* Just because it's in the Ticket doesn't make it authenticated */
|
||||
if (authenticated)
|
||||
*authenticated = 0;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
if (value) {
|
||||
ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length,
|
||||
ticket->authorization_data, &sz, kret);
|
||||
*minor_status = kret;
|
||||
}
|
||||
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"authenticator-authz-data") &&
|
||||
nameattrs && nameattrs->authenticator_ad) {
|
||||
size_t sz;
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = 0;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
if (value) {
|
||||
ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length,
|
||||
nameattrs->authenticator_ad, &sz, kret);
|
||||
*minor_status = kret;
|
||||
}
|
||||
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
||||
"transit-path") &&
|
||||
(ticket || (nameattrs && nameattrs->transited))) {
|
||||
size_t sz;
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = 1;
|
||||
if (complete)
|
||||
*complete = 1;
|
||||
|
||||
if (value && ticket)
|
||||
ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length,
|
||||
&ticket->transited, &sz, kret);
|
||||
else if (value && nameattrs->transited)
|
||||
ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length,
|
||||
nameattrs->transited, &sz, kret);
|
||||
*minor_status = kret;
|
||||
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
return GSS_S_UNAVAILABLE;
|
||||
|
||||
enomem:
|
||||
if (value)
|
||||
gss_release_buffer(minor_status, value);
|
||||
*minor_status = ENOMEM;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
static OM_uint32
|
||||
add_urn(OM_uint32 *minor_status,
|
||||
gss_name_t name,
|
||||
gss_buffer_t urn,
|
||||
gss_buffer_set_t *attrs)
|
||||
{
|
||||
OM_uint32 major;
|
||||
|
||||
major = _gsskrb5_get_name_attribute(minor_status, name, urn,
|
||||
0, 0, 0, 0, 0);
|
||||
if (major == GSS_S_COMPLETE) {
|
||||
major = gss_add_buffer_set_member(minor_status, urn, attrs);
|
||||
if (major)
|
||||
return major;
|
||||
}
|
||||
if (major == GSS_S_UNAVAILABLE)
|
||||
return GSS_S_COMPLETE;
|
||||
return major;
|
||||
}
|
||||
|
||||
#define ADD_URN(l) \
|
||||
do if (major == GSS_S_COMPLETE) { \
|
||||
if (strncmp(l, "urn:", sizeof("urn:") - 1) == 0) { \
|
||||
urn.value = l; \
|
||||
urn.length = sizeof(l) - 1; \
|
||||
} else { \
|
||||
urn.value = GSS_KRB5_NAME_ATTRIBUTE_BASE_URN l; \
|
||||
urn.length = sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN l) - 1;\
|
||||
} \
|
||||
major = add_urn(minor_status, name, &urn, attrs); \
|
||||
} while (0)
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV
|
||||
_gsskrb5_inquire_name(OM_uint32 *minor_status,
|
||||
gss_name_t name,
|
||||
int *name_is_MN,
|
||||
gss_OID *MN_mech,
|
||||
gss_buffer_set_t *attrs)
|
||||
{
|
||||
OM_uint32 major = GSS_S_COMPLETE;
|
||||
gss_buffer_desc urn;
|
||||
krb5_error_code ret;
|
||||
krb5_context context;
|
||||
char lname[32];
|
||||
|
||||
GSSAPI_KRB5_INIT(&context);
|
||||
|
||||
*minor_status = 0;
|
||||
if (name_is_MN)
|
||||
*name_is_MN = 1;
|
||||
if (MN_mech)
|
||||
*MN_mech = GSS_KRB5_MECHANISM;
|
||||
if (name == GSS_C_NO_NAME)
|
||||
return GSS_S_CALL_INACCESSIBLE_READ;
|
||||
if (attrs == NULL)
|
||||
return GSS_S_CALL_INACCESSIBLE_WRITE;
|
||||
ADD_URN("realm");
|
||||
ADD_URN("name-ncomp");
|
||||
ADD_URN("name-ncomp#0");
|
||||
ADD_URN("name-ncomp#1");
|
||||
ADD_URN("name-ncomp#2");
|
||||
ADD_URN("name-ncomp#3");
|
||||
ADD_URN("name-ncomp#4");
|
||||
ADD_URN("name-ncomp#5");
|
||||
ADD_URN("name-ncomp#6");
|
||||
ADD_URN("name-ncomp#7");
|
||||
ADD_URN("name-ncomp#8");
|
||||
ADD_URN("name-ncomp#9");
|
||||
ADD_URN("peer-realm");
|
||||
ADD_URN("ticket-authz-data#pac");
|
||||
ADD_URN("urn:mspac:");
|
||||
ADD_URN("authenticator-authz-data"); /* XXX Add fragments? */
|
||||
ADD_URN("ticket-authz-data"); /* XXX Add fragments? */
|
||||
ADD_URN("authz-data");
|
||||
ADD_URN("transit-path");
|
||||
ADD_URN("canonical-name");
|
||||
major = GSS_S_COMPLETE;
|
||||
lname[0] = '\0';
|
||||
ret = krb5_aname_to_localname(context, (void *)name,
|
||||
sizeof(lname) - 1, lname);
|
||||
if (ret == 0 && lname[0] != '\0')
|
||||
major = gss_add_buffer_set_member(minor_status,
|
||||
GSS_C_ATTR_LOCAL_LOGIN_USER, attrs);
|
||||
return major;
|
||||
}
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV
|
||||
_gsskrb5_display_name_ext(OM_uint32 *minor_status,
|
||||
gss_name_t name,
|
||||
gss_OID display_as_name_type,
|
||||
gss_buffer_t display_name)
|
||||
{
|
||||
krb5_const_principal p = (void *)name;
|
||||
char *s = NULL;
|
||||
|
||||
*minor_status = 0;
|
||||
if (display_name == NULL)
|
||||
return GSS_S_CALL_INACCESSIBLE_WRITE;
|
||||
display_name->length = 0;
|
||||
display_name->value = NULL;
|
||||
|
||||
if (gss_oid_equal(display_as_name_type, GSS_C_NT_USER_NAME)) {
|
||||
if (p->name.name_string.len != 1)
|
||||
return GSS_S_UNAVAILABLE;
|
||||
return _gsskrb5_localname(minor_status, name, GSS_KRB5_MECHANISM,
|
||||
display_name);
|
||||
}
|
||||
if (!gss_oid_equal(display_as_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
|
||||
p->name.name_string.len != 2 ||
|
||||
strchr(p->name.name_string.val[0], '@') ||
|
||||
strchr(p->name.name_string.val[1], '.') == NULL)
|
||||
return GSS_S_UNAVAILABLE;
|
||||
if (asprintf(&s, "%s@%s", p->name.name_string.val[0],
|
||||
p->name.name_string.val[1]) == -1 || s == NULL) {
|
||||
*minor_status = ENOMEM;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
display_name->length = strlen(s);
|
||||
display_name->value = s;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
||||
|
||||
OM_uint32 GSSAPI_CALLCONV
|
||||
_gsskrb5_export_name_composite(OM_uint32 *minor_status,
|
||||
gss_name_t name,
|
||||
gss_buffer_t exported_name)
|
||||
{
|
||||
krb5_error_code kret;
|
||||
gss_buffer_desc inner = GSS_C_EMPTY_BUFFER;
|
||||
unsigned char *buf;
|
||||
size_t sz;
|
||||
|
||||
if (name == NULL)
|
||||
return GSS_S_CALL_INACCESSIBLE_READ;
|
||||
if (exported_name == NULL)
|
||||
return GSS_S_CALL_INACCESSIBLE_WRITE;
|
||||
|
||||
ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length,
|
||||
(void *)name, &sz, kret);
|
||||
if (kret != 0) {
|
||||
*minor_status = kret;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length;
|
||||
exported_name->value = malloc(exported_name->length);
|
||||
if (exported_name->value == NULL) {
|
||||
free(inner.value);
|
||||
*minor_status = ENOMEM;
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
/* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
|
||||
|
||||
buf = exported_name->value;
|
||||
buf[0] = 0x04;
|
||||
buf[1] = 0x02;
|
||||
buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff;
|
||||
buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff;
|
||||
buf[4] = 0x06;
|
||||
buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF;
|
||||
|
||||
memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length);
|
||||
buf += 6 + GSS_KRB5_MECHANISM->length;
|
||||
|
||||
buf[0] = (inner.length >> 24) & 0xff;
|
||||
buf[1] = (inner.length >> 16) & 0xff;
|
||||
buf[2] = (inner.length >> 8) & 0xff;
|
||||
buf[3] = (inner.length) & 0xff;
|
||||
buf += 4;
|
||||
|
||||
memcpy(buf, inner.value, inner.length);
|
||||
free(inner.value);
|
||||
|
||||
*minor_status = 0;
|
||||
return GSS_S_COMPLETE;
|
||||
}
|
Reference in New Issue
Block a user