kdc: add canonical principal name to authz data

Use the UPN_DNS_INFO buffer of the PAC to include the canonical principal name.

Arguably we should use AD-LOGIN-ALIAS as defined in RFC6806, but we may not
always know all the principal's aliases, and this approach allows us to share
application service logic with Windows.
This commit is contained in:
Luke Howard
2021-12-19 16:02:58 +11:00
parent 0ab3b7b2dd
commit e50033aec2
8 changed files with 198 additions and 20 deletions

View File

@@ -843,6 +843,7 @@ EXPORTS
_krb5_expand_path_tokens ;!
_krb5_make_pa_enc_challenge
_krb5_validate_pa_enc_challenge
_krb5_store_utf8_as_ucs2le_at_offset
; kinit helper
krb5_get_init_creds_opt_set_pkinit_user_certs

View File

@@ -671,18 +671,23 @@ parse_upn_dns_info(krb5_context context,
CHECK(ret, krb5_ret_uint16(sp, &sam_name_offset), out);
CHECK(ret, krb5_ret_uint16(sp, &sid_length), out);
CHECK(ret, krb5_ret_uint16(sp, &sid_offset), out);
} else {
sam_name_offset = 0;
sid_offset = 0;
}
CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, upn_offset,
upn_length, &upn), out);
if (upn_offset) {
CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, upn_offset,
upn_length, &upn), out);
}
CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, dns_domain_name_offset,
dns_domain_name_length, &dns_domain_name), out);
if (*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) {
if ((*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) && sam_name_offset) {
CHECK(ret, _krb5_ret_utf8_from_ucs2le_at_offset(sp, sam_name_offset,
sam_name_length, &sam_name), out);
}
if (upn_length) {
if (upn_offset) {
ret = krb5_parse_name_flags(context,
upn,
KRB5_PRINCIPAL_PARSE_ENTERPRISE |
@@ -696,7 +701,7 @@ parse_upn_dns_info(krb5_context context,
goto out;
}
if (*flags & PAC_EXTRA_LOGON_INFO_FLAGS_HAS_SAM_NAME_AND_SID) {
if (sam_name_offset) {
ret = krb5_parse_name_flags(context,
sam_name,
KRB5_PRINCIPAL_PARSE_NO_REALM |
@@ -708,16 +713,18 @@ parse_upn_dns_info(krb5_context context,
ret = krb5_principal_set_realm(context, *sam_name_princ, dns_domain_name);
if (ret)
goto out;
CHECK(ret, _krb5_ret_data_at_offset(sp, sid_offset, sid_length, sid), out);
}
if (sid_offset)
CHECK(ret, _krb5_ret_data_at_offset(sp, sid_offset, sid_length, sid), out);
out:
free(upn);
free(dns_domain_name);
free(sam_name);
krb5_storage_free(sp);
return ret;
}
@@ -762,8 +769,7 @@ build_upn_dns_info(krb5_context context,
if (canon_princ) {
ret = krb5_unparse_name_flags(context, canon_princ,
KRB5_PRINCIPAL_UNPARSE_NO_REALM |
KRB5_PRINCIPAL_UNPARSE_DISPLAY,
KRB5_PRINCIPAL_UNPARSE_NO_REALM,
&canon_princ_name);
if (ret)
goto out;
@@ -805,6 +811,7 @@ out:
krb5_xfree(canon_princ_name);
krb5_xfree(upn_princ_name);
krb5_storage_free(sp);
return ret;
}

View File

@@ -1864,7 +1864,7 @@ cleanup:
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_ret_utf8_from_ucs2le_at_offset(krb5_storage *sp,
size_t offset,
off_t offset,
size_t length,
char **utf8)
{
@@ -1919,3 +1919,109 @@ out:
return ret;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_store_data_at_offset(krb5_storage *sp,
size_t offset,
const krb5_data *data)
{
krb5_error_code ret;
krb5_ssize_t nbytes;
off_t pos;
if (offset == (off_t)-1) {
if (data == NULL || data->data == NULL) {
offset = 0;
} else {
pos = sp->seek(sp, 0, SEEK_CUR);
offset = sp->seek(sp, 0, SEEK_END);
sp->seek(sp, pos, SEEK_SET);
if (offset == (off_t)-1)
return HEIM_ERR_NOT_SEEKABLE;
}
}
if (offset > 0xFFFF)
return ERANGE;
else if ((offset != 0) != (data && data->data))
return EINVAL;
else if (data && data->length > 0xFFFF)
return ERANGE;
ret = krb5_store_uint16(sp, data ? (uint16_t)data->length : 0);
if (ret == 0)
ret = krb5_store_uint16(sp, (uint16_t)offset);
if (ret == 0 && offset) {
pos = sp->seek(sp, 0, SEEK_CUR);
sp->seek(sp, offset, SEEK_SET);
nbytes = krb5_storage_write(sp, data->data, data->length);
if ((size_t)nbytes != data->length)
ret = sp->eof_code;
sp->seek(sp, pos, SEEK_SET);
}
return ret;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
_krb5_store_utf8_as_ucs2le_at_offset(krb5_storage *sp,
off_t offset,
const char *utf8)
{
krb5_error_code ret;
size_t ucs2_len, ucs2le_size;
uint16_t *ucs2, *ucs2le;
unsigned int flags;
if (utf8) {
ret = wind_utf8ucs2_length(utf8, &ucs2_len);
if (ret)
return ret;
ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
if (ucs2 == NULL)
return ENOMEM;
ret = wind_utf8ucs2(utf8, ucs2, &ucs2_len);
if (ret) {
free(ucs2);
return ret;
}
ucs2le_size = (ucs2_len + 1) * 2;
ucs2le = malloc(ucs2le_size);
if (ucs2le == NULL) {
free(ucs2);
return ENOMEM;
}
flags = WIND_RW_LE;
ret = wind_ucs2write(ucs2, ucs2_len, &flags, ucs2le, &ucs2le_size);
free(ucs2);
if (ret) {
free(ucs2le);
return ret;
}
ucs2le_size = ucs2_len * 2;
} else {
ucs2le = NULL;
ucs2le_size = 0;
offset = 0;
ret = 0;
}
{
krb5_data data;
data.data = ucs2le;
data.length = ucs2le_size;
ret = _krb5_store_data_at_offset(sp, offset, &data);
}
free(ucs2le);
return ret;
}

View File

@@ -833,6 +833,7 @@ HEIMDAL_KRB5_2.0 {
_krb5_crypto_set_flags;
_krb5_make_pa_enc_challenge;
_krb5_validate_pa_enc_challenge;
_krb5_store_utf8_as_ucs2le_at_offset;
# kinit helper
krb5_get_init_creds_opt_set_pkinit_user_certs;