gss: expose PAC info buffers under urn:mspac:
Expose PAC info buffers using naming attributes prefixed with urn:mspac:, aligned with MIT.
This commit is contained in:
@@ -383,6 +383,7 @@ LDADD = libgssapi.la \
|
|||||||
$(LIB_roken)
|
$(LIB_roken)
|
||||||
|
|
||||||
test_names_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la
|
test_names_LDADD = $(LDADD) $(top_builddir)/lib/asn1/libasn1.la
|
||||||
|
test_context_LDADD = $(LDADD) $(top_builddir)/lib/wind/libwind.la
|
||||||
|
|
||||||
# gss
|
# gss
|
||||||
|
|
||||||
|
@@ -71,7 +71,7 @@
|
|||||||
*
|
*
|
||||||
* Compatibility with MIT:
|
* Compatibility with MIT:
|
||||||
*
|
*
|
||||||
* - "urn:mspac:" -> the PAC
|
* - "urn:mspac:" -> the PAC and its individual info buffers
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
*
|
*
|
||||||
@@ -80,25 +80,25 @@
|
|||||||
* alternative raw and/or display value encodings (JSON?)
|
* alternative raw and/or display value encodings (JSON?)
|
||||||
* - Add support for attributes for accessing other parts of the Ticket / KDC
|
* - Add support for attributes for accessing other parts of the Ticket / KDC
|
||||||
* reply enc-parts, like auth times
|
* reply enc-parts, like auth times
|
||||||
* - Add support for getting specific PAC buffers
|
* - Add support for getting PAC logon fields, including SIDs (one at a time)
|
||||||
* - Add support for getting PAC login fields, including SIDs (one at a time)
|
|
||||||
* - Add support for CAMMAC?
|
* - Add support for CAMMAC?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
attr_eq(gss_buffer_t attr, const char *aname, size_t aname_len)
|
attr_eq(gss_buffer_t attr, const char *aname, size_t aname_len,
|
||||||
|
int prefix_check)
|
||||||
{
|
{
|
||||||
const char *s;
|
|
||||||
|
|
||||||
if (attr->length < aname_len)
|
if (attr->length < aname_len)
|
||||||
return 0;
|
return 0;
|
||||||
/* Note: `s' is not NUL-terminated */
|
|
||||||
s = ((const char *)attr->value) + attr->length - aname_len;
|
if (strncmp((char *)attr->value, aname, aname_len) != 0)
|
||||||
return strncmp(s, aname, aname_len) == 0 &&
|
return 0;
|
||||||
(attr->length == aname_len || s[aname_len] == '#');
|
|
||||||
|
return prefix_check || attr->length == aname_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1))
|
#define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1, FALSE))
|
||||||
|
#define ATTR_EQ_PREFIX(a, an) (attr_eq(a, an, sizeof(an) - 1, TRUE))
|
||||||
|
|
||||||
/* Split attribute into prefix, suffix, and fragment. See RFC6680. */
|
/* Split attribute into prefix, suffix, and fragment. See RFC6680. */
|
||||||
static void
|
static void
|
||||||
@@ -394,17 +394,25 @@ _gsskrb5_get_name_attribute(OM_uint32 *minor_status,
|
|||||||
if (kret == ENOENT)
|
if (kret == ENOENT)
|
||||||
return GSS_S_UNAVAILABLE;
|
return GSS_S_UNAVAILABLE;
|
||||||
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||||
} else if ((ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
} else if (ticket && ticket->authorization_data &&
|
||||||
"ticket-authz-data#pac") ||
|
(ATTR_EQ_PREFIX(&attr, "urn:mspac:") ||
|
||||||
ATTR_EQ(&attr, "urn:mspac:")) &&
|
(ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "ticket-authz-data") &&
|
||||||
ticket && ticket->authorization_data) {
|
(ATTR_EQ(&frag, "pac") || ATTR_EQ_PREFIX(&frag, "pac-"))))) {
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_data data;
|
krb5_data data, pac_data, *datap;
|
||||||
|
krb5_data suffix;
|
||||||
|
|
||||||
|
if (ATTR_EQ_PREFIX(&attr, "urn:mspac:")) {
|
||||||
|
suffix.length = attr.length - (sizeof("urn:mspac:") - 1);
|
||||||
|
suffix.data = (char *)attr.value + sizeof("urn:mspac:") - 1;
|
||||||
|
} else if (ATTR_EQ_PREFIX(&frag, "pac-")) {
|
||||||
|
suffix.length = frag.length - sizeof("pac-") - 1;
|
||||||
|
suffix.data = (char *)frag.value + sizeof("pac-") - 1;
|
||||||
|
} else
|
||||||
|
krb5_data_zero(&suffix); /* ticket-authz-data#pac */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In MIT the attribute for the whole PAC is "urn:mspac:".
|
* 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);
|
GSSAPI_KRB5_INIT(&context);
|
||||||
@@ -414,22 +422,39 @@ _gsskrb5_get_name_attribute(OM_uint32 *minor_status,
|
|||||||
if (complete)
|
if (complete)
|
||||||
*complete = 1;
|
*complete = 1;
|
||||||
|
|
||||||
|
if (suffix.length)
|
||||||
|
datap = &pac_data;
|
||||||
|
else if (value)
|
||||||
|
datap = &data;
|
||||||
|
else
|
||||||
|
datap = NULL;
|
||||||
|
|
||||||
kret = _krb5_get_ad(context, ticket->authorization_data,
|
kret = _krb5_get_ad(context, ticket->authorization_data,
|
||||||
NULL, KRB5_AUTHDATA_WIN2K_PAC,
|
NULL, KRB5_AUTHDATA_WIN2K_PAC, datap);
|
||||||
value ? &data : NULL);
|
if (kret == 0 && suffix.length) {
|
||||||
|
krb5_pac pac;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
krb5_data_free(&pac_data);
|
||||||
|
}
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
value->length = data.length;
|
value->length = data.length;
|
||||||
value->value = data.data;
|
value->value = data.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
*minor_status = kret;
|
*minor_status = kret;
|
||||||
if (kret == ENOENT)
|
if (kret == ENOENT)
|
||||||
return GSS_S_UNAVAILABLE;
|
return GSS_S_UNAVAILABLE;
|
||||||
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
|
||||||
} else if (ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN
|
} else if (ticket && ticket->authorization_data &&
|
||||||
"ticket-authz-data#kdc-issued") &&
|
ATTR_EQ(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN "ticket-authz-data") &&
|
||||||
ticket &&
|
ATTR_EQ(&frag, "kdc-issued")) {
|
||||||
ticket->authorization_data) {
|
|
||||||
krb5_context context;
|
krb5_context context;
|
||||||
krb5_data data;
|
krb5_data data;
|
||||||
|
|
||||||
@@ -583,7 +608,25 @@ _gsskrb5_inquire_name(OM_uint32 *minor_status,
|
|||||||
ADD_URN("name-ncomp#9");
|
ADD_URN("name-ncomp#9");
|
||||||
ADD_URN("peer-realm");
|
ADD_URN("peer-realm");
|
||||||
ADD_URN("ticket-authz-data#pac");
|
ADD_URN("ticket-authz-data#pac");
|
||||||
|
ADD_URN("ticket-authz-data#pac-logon-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-credentials-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-server-checksum");
|
||||||
|
ADD_URN("ticket-authz-data#pac-privsvr-checksum");
|
||||||
|
ADD_URN("ticket-authz-data#pac-client-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-delegation-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-upn-dns-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-attributes-info");
|
||||||
|
ADD_URN("ticket-authz-data#pac-requestor-sid");
|
||||||
ADD_URN("urn:mspac:");
|
ADD_URN("urn:mspac:");
|
||||||
|
ADD_URN("urn:mspac:logon-info");
|
||||||
|
ADD_URN("urn:mspac:credentials-info");
|
||||||
|
ADD_URN("urn:mspac:server-checksum");
|
||||||
|
ADD_URN("urn:mspac:privsvr-checksum");
|
||||||
|
ADD_URN("urn:mspac:client-info");
|
||||||
|
ADD_URN("urn:mspac:delegation-info");
|
||||||
|
ADD_URN("urn:mspac:upn-dns-info");
|
||||||
|
ADD_URN("urn:mspac:attributes-info");
|
||||||
|
ADD_URN("urn:mspac:requestor-sid");
|
||||||
ADD_URN("authenticator-authz-data"); /* XXX Add fragments? */
|
ADD_URN("authenticator-authz-data"); /* XXX Add fragments? */
|
||||||
ADD_URN("ticket-authz-data"); /* XXX Add fragments? */
|
ADD_URN("ticket-authz-data"); /* XXX Add fragments? */
|
||||||
ADD_URN("authz-data");
|
ADD_URN("authz-data");
|
||||||
|
@@ -134,6 +134,87 @@ string_to_oids(gss_OID_set *oidsetp, char *names)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
show_pac_client_info(gss_name_t n)
|
||||||
|
{
|
||||||
|
gss_buffer_desc dv = GSS_C_EMPTY_BUFFER;
|
||||||
|
gss_buffer_desc v = GSS_C_EMPTY_BUFFER;
|
||||||
|
gss_buffer_desc a;
|
||||||
|
OM_uint32 maj, min;
|
||||||
|
int authenticated, complete, more;
|
||||||
|
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_storage *sp = NULL;
|
||||||
|
uint16_t len = 0, *s;
|
||||||
|
uint64_t tmp;
|
||||||
|
char *logon_string = NULL;
|
||||||
|
|
||||||
|
a.value = "urn:mspac:client-info";
|
||||||
|
a.length = strlen((char *)a.value);
|
||||||
|
more = 0;
|
||||||
|
maj = gss_get_name_attribute(&min, n, &a, &authenticated, &complete, &v,
|
||||||
|
&dv, &more);
|
||||||
|
if (maj != GSS_S_COMPLETE)
|
||||||
|
errx(1, "gss_get_name_attribute: %s",
|
||||||
|
gssapi_err(maj, min, GSS_KRB5_MECHANISM));
|
||||||
|
|
||||||
|
|
||||||
|
sp = krb5_storage_from_readonly_mem(v.value, v.length);
|
||||||
|
if (sp == NULL)
|
||||||
|
errx(1, "show_pac_client_info: out of memory");
|
||||||
|
|
||||||
|
krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
|
||||||
|
|
||||||
|
ret = krb5_ret_uint64(sp, &tmp); /* skip over time */
|
||||||
|
if (ret == 0)
|
||||||
|
ret = krb5_ret_uint16(sp, &len);
|
||||||
|
if (ret || len == 0)
|
||||||
|
errx(1, "show_pac_client_info: invalid PAC logon info length");
|
||||||
|
|
||||||
|
s = malloc(len);
|
||||||
|
ret = krb5_storage_read(sp, s, len);
|
||||||
|
if (ret != len)
|
||||||
|
errx(1, "show_pac_client_info:, failed to read PAC logon name");
|
||||||
|
|
||||||
|
krb5_storage_free(sp);
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t ucs2len = len / 2;
|
||||||
|
uint16_t *ucs2;
|
||||||
|
size_t u8len;
|
||||||
|
unsigned int flags = WIND_RW_LE;
|
||||||
|
|
||||||
|
ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
|
||||||
|
if (ucs2 == NULL)
|
||||||
|
errx(1, "show_pac_client_info: out of memory");
|
||||||
|
|
||||||
|
ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
|
||||||
|
free(s);
|
||||||
|
if (ret)
|
||||||
|
errx(1, "failed to convert string to UCS-2");
|
||||||
|
|
||||||
|
ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
|
||||||
|
if (ret)
|
||||||
|
errx(1, "failed to count length of UCS-2 string");
|
||||||
|
|
||||||
|
u8len += 1; /* Add space for NUL */
|
||||||
|
logon_string = malloc(u8len);
|
||||||
|
if (logon_string == NULL)
|
||||||
|
errx(1, "show_pac_client_info: out of memory");
|
||||||
|
|
||||||
|
ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
|
||||||
|
free(ucs2);
|
||||||
|
if (ret)
|
||||||
|
errx(1, "failed to convert to UTF-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("logon name: %s\n", logon_string);
|
||||||
|
free(logon_string);
|
||||||
|
|
||||||
|
gss_release_buffer(&min, &dv);
|
||||||
|
gss_release_buffer(&min, &v);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
loop(gss_OID mechoid,
|
loop(gss_OID mechoid,
|
||||||
gss_OID nameoid, const char *target,
|
gss_OID nameoid, const char *target,
|
||||||
@@ -393,6 +474,8 @@ loop(gss_OID mechoid,
|
|||||||
} else
|
} else
|
||||||
warnx("display_name: %s",
|
warnx("display_name: %s",
|
||||||
gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
|
gssapi_err(maj_stat, min_stat, GSS_C_NO_OID));
|
||||||
|
if (gss_oid_equal(actual_mech_server, GSS_KRB5_MECHANISM))
|
||||||
|
show_pac_client_info(src_name);
|
||||||
}
|
}
|
||||||
gss_release_name(&min_stat, &src_name);
|
gss_release_name(&min_stat, &src_name);
|
||||||
|
|
||||||
|
@@ -500,6 +500,7 @@ EXPORTS
|
|||||||
krb5_pac_add_buffer
|
krb5_pac_add_buffer
|
||||||
krb5_pac_free
|
krb5_pac_free
|
||||||
krb5_pac_get_buffer
|
krb5_pac_get_buffer
|
||||||
|
_krb5_pac_get_buffer_by_name
|
||||||
krb5_pac_get_kdc_checksum_info
|
krb5_pac_get_kdc_checksum_info
|
||||||
krb5_pac_get_types
|
krb5_pac_get_types
|
||||||
krb5_pac_init
|
krb5_pac_init
|
||||||
|
@@ -73,6 +73,8 @@ struct krb5_pac_data {
|
|||||||
#define PACTYPE_SIZE 8
|
#define PACTYPE_SIZE 8
|
||||||
#define PAC_INFO_BUFFER_SIZE 16
|
#define PAC_INFO_BUFFER_SIZE 16
|
||||||
|
|
||||||
|
#define PAC_LOGON_INFO 1
|
||||||
|
#define PAC_CREDENTIALS_INFO 2
|
||||||
#define PAC_SERVER_CHECKSUM 6
|
#define PAC_SERVER_CHECKSUM 6
|
||||||
#define PAC_PRIVSVR_CHECKSUM 7
|
#define PAC_PRIVSVR_CHECKSUM 7
|
||||||
#define PAC_LOGON_NAME 10
|
#define PAC_LOGON_NAME 10
|
||||||
@@ -432,11 +434,14 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p,
|
|||||||
if (p->pac->buffers[i].type != type)
|
if (p->pac->buffers[i].type != type)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
|
if (data) {
|
||||||
if (ret) {
|
ret = krb5_data_copy(data, (unsigned char *)p->data.data + offset, len);
|
||||||
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
|
if (ret) {
|
||||||
return ret;
|
krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
|
krb5_set_error_message(context, ENOENT, "No PAC buffer of type %lu was found",
|
||||||
@@ -444,6 +449,45 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p,
|
|||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
uint32_t type;
|
||||||
|
krb5_data name;
|
||||||
|
} pac_buffer_name_map[] = {
|
||||||
|
#define PAC_MAP_ENTRY(type, name) { PAC_##type, { sizeof(name) - 1, name } }
|
||||||
|
PAC_MAP_ENTRY(LOGON_INFO, "logon-info" ),
|
||||||
|
PAC_MAP_ENTRY(CREDENTIALS_INFO, "credentials-info" ),
|
||||||
|
PAC_MAP_ENTRY(SERVER_CHECKSUM, "server-checksum" ),
|
||||||
|
PAC_MAP_ENTRY(PRIVSVR_CHECKSUM, "privsvr-checksum" ),
|
||||||
|
PAC_MAP_ENTRY(LOGON_NAME, "client-info" ),
|
||||||
|
PAC_MAP_ENTRY(CONSTRAINED_DELEGATION, "delegation-info" ),
|
||||||
|
PAC_MAP_ENTRY(UPN_DNS_INFO, "upn-dns-info" ),
|
||||||
|
PAC_MAP_ENTRY(TICKET_CHECKSUM, "ticket-checksum" ),
|
||||||
|
PAC_MAP_ENTRY(ATTRIBUTES_INFO, "attributes-info" ),
|
||||||
|
PAC_MAP_ENTRY(REQUESTOR_SID, "requestor-sid" )
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
|
||||||
|
_krb5_pac_get_buffer_by_name(krb5_context context, krb5_pac p,
|
||||||
|
const krb5_data *name, krb5_data *data)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
i < sizeof(pac_buffer_name_map) / sizeof(pac_buffer_name_map[0]);
|
||||||
|
i++) {
|
||||||
|
if (krb5_data_cmp(name, &pac_buffer_name_map[i].name) == 0)
|
||||||
|
return krb5_pac_get_buffer(context, p, pac_buffer_name_map[i].type, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_set_error_message(context, ENOENT, "No PAC buffer with name %.*s was found",
|
||||||
|
(int)name->length, (char *)name->data);
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@@ -493,6 +493,7 @@ HEIMDAL_KRB5_2.0 {
|
|||||||
krb5_pac_add_buffer;
|
krb5_pac_add_buffer;
|
||||||
krb5_pac_free;
|
krb5_pac_free;
|
||||||
krb5_pac_get_buffer;
|
krb5_pac_get_buffer;
|
||||||
|
_krb5_pac_get_buffer_by_name;
|
||||||
krb5_pac_get_kdc_checksum_info;
|
krb5_pac_get_kdc_checksum_info;
|
||||||
krb5_pac_get_types;
|
krb5_pac_get_types;
|
||||||
krb5_pac_init;
|
krb5_pac_init;
|
||||||
|
Reference in New Issue
Block a user