Merge pull request #138 from abartlet/lorikeet-heimdal-for-upstream

Samba Cross-realm support patches from metze

These patches were posted to heimdal-discuss by metze, and there were no objections there.
This commit is contained in:
Andrew Bartlett
2015-07-31 18:03:07 +12:00
15 changed files with 1963 additions and 75 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -244,8 +244,9 @@ _kdc_fast_mk_error(krb5_context context,
const KDC_REQ_BODY *req_body,
krb5_error_code outer_error,
const char *e_text,
krb5_principal error_client,
krb5_principal error_server,
const PrincipalName *error_client_name,
const Realm *error_client_realm,
time_t *csec, int *cusec,
krb5_data *error_msg)
{
@@ -264,15 +265,16 @@ _kdc_fast_mk_error(krb5_context context,
/* first add the KRB-ERROR to the fast errors */
ret = krb5_mk_error(context,
outer_error,
e_text,
NULL,
error_client,
error_server,
NULL,
NULL,
&e_data);
ret = krb5_mk_error_ext(context,
outer_error,
e_text,
NULL,
error_server,
error_client_name,
error_client_realm,
NULL,
NULL,
&e_data);
if (ret)
return ret;
@@ -285,7 +287,8 @@ _kdc_fast_mk_error(krb5_context context,
}
if (/* hide_principal */ 0) {
error_client = NULL;
error_client_name = NULL;
error_client_realm = NULL;
error_server = NULL;
e_text = NULL;
}
@@ -325,15 +328,16 @@ _kdc_fast_mk_error(krb5_context context,
krb5_abortx(context, "internal asn.1 error");
}
ret = krb5_mk_error(context,
outer_error,
e_text,
(e_data.length ? &e_data : NULL),
error_client,
error_server,
csec,
cusec,
error_msg);
ret = krb5_mk_error_ext(context,
outer_error,
e_text,
(e_data.length ? &e_data : NULL),
error_server,
error_client_name,
error_client_realm,
csec,
cusec,
error_msg);
krb5_data_free(&e_data);
return ret;

View File

@@ -1712,6 +1712,31 @@ _kdc_as_rep(kdc_request_t r,
kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy",
r->client_name);
goto out;
} else if (ret == HDB_ERR_WRONG_REALM) {
char *fixed_client_name = NULL;
ret = krb5_unparse_name(context, r->client->entry.principal,
&fixed_client_name);
if (ret) {
goto out;
}
kdc_log(context, config, 0, "WRONG_REALM - %s -> %s",
r->client_name, fixed_client_name);
free(fixed_client_name);
ret = _kdc_fast_mk_error(context, r,
&error_method,
r->armor_crypto,
&req->req_body,
KRB5_KDC_ERR_WRONG_REALM,
NULL,
r->server_princ,
NULL,
&r->client->entry.principal->realm,
NULL, NULL,
reply);
goto out;
} else if(ret){
const char *msg = krb5_get_error_message(context, ret);
kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg);
@@ -2193,13 +2218,15 @@ out:
/*
* In case of a non proxy error, build an error message.
*/
if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) {
if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && reply->length == 0) {
ret = _kdc_fast_mk_error(context, r,
&error_method,
r->armor_crypto,
&req->req_body,
ret, r->e_text,
r->client_princ, r->server_princ,
r->server_princ,
&r->client_princ->name,
&r->client_princ->realm,
NULL, NULL,
reply);
if (ret)

View File

@@ -1121,15 +1121,14 @@ need_referral(krb5_context context, krb5_kdc_configuration *config,
if (server->name.name_string.len == 1)
name = server->name.name_string.val[0];
else if (server->name.name_string.len == 3 &&
strcasecmp("E3514235-4B06-11D1-AB04-00C04FC2DCD2", server->name.name_string.val[0]) == 0) {
else if (server->name.name_string.len == 3) {
/*
This is used to give referrals for the
E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
SPN form, which is used for inter-domain communication in AD
*/
name = server->name.name_string.val[2];
kdc_log(context, config, 0, "Giving 3 part DRSUAPI referral for %s", name);
kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
*realms = malloc(sizeof(char *)*2);
if (*realms == NULL) {
krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
@@ -1648,6 +1647,32 @@ server_lookup:
if(ret == HDB_ERR_NOT_FOUND_HERE) {
kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
goto out;
} else if (ret == HDB_ERR_WRONG_REALM) {
if (ref_realm)
free(ref_realm);
ref_realm = strdup(server->entry.principal->realm);
if (ref_realm == NULL) {
ret = ENOMEM;
goto out;
}
kdc_log(context, config, 5,
"Returning a referral to realm %s for "
"server %s.",
ref_realm, spn);
krb5_free_principal(context, sp);
sp = NULL;
free(spn);
spn = NULL;
ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
ref_realm, NULL);
if (ret)
goto out;
ret = krb5_unparse_name(context, sp, &spn);
if (ret)
goto out;
goto server_lookup;
} else if(ret){
const char *new_rlm, *msg;
Realm req_rlm;
@@ -2457,6 +2482,7 @@ out:
NULL,
NULL,
ret, NULL,
NULL,
NULL, NULL,
csec, cusec,
data);

View File

@@ -101,6 +101,13 @@ _kdc_db_fetch(krb5_context context,
config->db[i]->hdb_close(context, config->db[i]);
switch (ret) {
case HDB_ERR_WRONG_REALM:
/*
* the ent->entry.principal just contains hints for the client
* to retry. This is important for enterprise principal routing
* between trusts.
*/
/* fall through */
case 0:
if (db)
*db = config->db[i];

View File

@@ -44,17 +44,43 @@ _gk_wrap_iov(OM_uint32 * minor_status,
gss_iov_buffer_desc *iov,
int iov_count)
{
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
OM_uint32 ret;
krb5_keyblock *key;
krb5_keytype keytype;
GSSAPI_KRB5_INIT (&context);
GSSAPI_KRB5_INIT (&context);
if (ctx->more_flags & IS_CFX)
return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
conf_req_flag, conf_state,
iov, iov_count);
if (ctx->more_flags & IS_CFX)
return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
conf_req_flag, conf_state,
iov, iov_count);
return GSS_S_FAILURE;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
krb5_enctype_to_keytype(context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context,
conf_req_flag, conf_state,
iov, iov_count, key);
break;
default:
ret = GSS_S_FAILURE;
break;
}
krb5_free_keyblock(context, key);
return ret;
}
OM_uint32 GSSAPI_CALLCONV
@@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
{
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
OM_uint32 ret;
krb5_keytype keytype;
krb5_keyblock *key;
GSSAPI_KRB5_INIT (&context);
@@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
return _gssapi_unwrap_cfx_iov(minor_status, ctx, context,
conf_state, qop_state, iov, iov_count);
return GSS_S_FAILURE;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
krb5_enctype_to_keytype(context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context,
conf_state, qop_state,
iov, iov_count, key);
break;
default:
ret = GSS_S_FAILURE;
break;
}
krb5_free_keyblock(context, key);
return ret;
}
OM_uint32 GSSAPI_CALLCONV
@@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
{
const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
krb5_context context;
OM_uint32 ret;
krb5_keytype keytype;
krb5_keyblock *key;
GSSAPI_KRB5_INIT (&context);
@@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
conf_req_flag, qop_req, conf_state,
iov, iov_count);
return GSS_S_FAILURE;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gsskrb5i_get_token_key(ctx, context, &key);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret) {
*minor_status = ret;
return GSS_S_FAILURE;
}
krb5_enctype_to_keytype(context, key->keytype, &keytype);
switch (keytype) {
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context,
conf_req_flag, qop_req, conf_state,
iov, iov_count);
break;
default:
ret = GSS_S_FAILURE;
break;
}
krb5_free_keyblock(context, key);
return ret;
}

View File

@@ -69,7 +69,7 @@
static krb5_error_code
arcfour_mic_key(krb5_context context, krb5_keyblock *key,
void *cksum_data, size_t cksum_size,
const void *cksum_data, size_t cksum_size,
void *key6_data, size_t key6_size)
{
krb5_error_code ret;
@@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key,
static krb5_error_code
arcfour_mic_cksum(krb5_context context,
krb5_keyblock *key, unsigned usage,
u_char *sgn_cksum, size_t sgn_cksum_sz,
const u_char *v1, size_t l1,
const void *v2, size_t l2,
const void *v3, size_t l3)
arcfour_mic_cksum_iov(krb5_context context,
krb5_keyblock *key, unsigned usage,
u_char *sgn_cksum, size_t sgn_cksum_sz,
const u_char *v1, size_t l1,
const void *v2, size_t l2,
const gss_iov_buffer_desc *iov,
int iov_count,
const gss_iov_buffer_desc *padding)
{
Checksum CKSUM;
u_char *ptr;
size_t len;
size_t ofs = 0;
int i;
krb5_crypto crypto;
krb5_error_code ret;
assert(sgn_cksum_sz == 8);
len = l1 + l2 + l3;
len = l1 + l2;
for (i=0; i < iov_count; i++) {
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_DATA:
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
break;
default:
continue;
}
len += iov[i].buffer.length;
}
if (padding) {
len += padding->buffer.length;
}
ptr = malloc(len);
if (ptr == NULL)
return ENOMEM;
memcpy(ptr, v1, l1);
memcpy(ptr + l1, v2, l2);
memcpy(ptr + l1 + l2, v3, l3);
memcpy(ptr + ofs, v1, l1);
ofs += l1;
memcpy(ptr + ofs, v2, l2);
ofs += l2;
for (i=0; i < iov_count; i++) {
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_DATA:
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
break;
default:
continue;
}
memcpy(ptr + ofs,
iov[i].buffer.value,
iov[i].buffer.length);
ofs += iov[i].buffer.length;
}
if (padding) {
memcpy(ptr + ofs,
padding->buffer.value,
padding->buffer.length);
ofs += padding->buffer.length;
}
ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret) {
@@ -149,6 +192,7 @@ arcfour_mic_cksum(krb5_context context,
0,
ptr, len,
&CKSUM);
memset(ptr, 0, len);
free(ptr);
if (ret == 0) {
memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
@@ -159,6 +203,26 @@ arcfour_mic_cksum(krb5_context context,
return ret;
}
static krb5_error_code
arcfour_mic_cksum(krb5_context context,
krb5_keyblock *key, unsigned usage,
u_char *sgn_cksum, size_t sgn_cksum_sz,
const u_char *v1, size_t l1,
const void *v2, size_t l2,
const void *v3, size_t l3)
{
gss_iov_buffer_desc iov;
iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
iov.buffer.value = rk_UNCONST(v3);
iov.buffer.length = l3;
return arcfour_mic_cksum_iov(context, key, usage,
sgn_cksum, sgn_cksum_sz,
v1, l1, v2, l2,
&iov, 1, NULL);
}
OM_uint32
_gssapi_get_mic_arcfour(OM_uint32 * minor_status,
@@ -760,3 +824,562 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
return GSS_S_COMPLETE;
}
OM_uint32
_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
gsskrb5_ctx ctx,
krb5_context context,
int conf_req_flag,
gss_qop_t qop_req,
int *conf_state,
gss_iov_buffer_desc *iov,
int iov_count)
{
OM_uint32 major_status;
size_t data_len = 0;
int i;
gss_iov_buffer_desc *header = NULL;
gss_iov_buffer_desc *padding = NULL;
gss_iov_buffer_desc *trailer = NULL;
*minor_status = 0;
for (i = 0; i < iov_count; i++) {
switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_EMPTY:
break;
case GSS_IOV_BUFFER_TYPE_DATA:
data_len += iov[i].buffer.length;
break;
case GSS_IOV_BUFFER_TYPE_HEADER:
if (header != NULL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
header = &iov[i];
break;
case GSS_IOV_BUFFER_TYPE_TRAILER:
if (trailer != NULL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
trailer = &iov[i];
break;
case GSS_IOV_BUFFER_TYPE_PADDING:
if (padding != NULL) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
padding = &iov[i];
break;
case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
break;
default:
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
}
major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
if (IS_DCE_STYLE(ctx)) {
size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
size_t total_len;
_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
header->buffer.length = total_len;
} else {
size_t len;
size_t total_len;
if (padding) {
data_len += 1; /* padding */
}
len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
header->buffer.length = total_len - data_len;
}
if (trailer) {
trailer->buffer.length = 0;
}
if (padding) {
padding->buffer.length = 1;
}
return GSS_S_COMPLETE;
}
OM_uint32
_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
gsskrb5_ctx ctx,
krb5_context context,
int conf_req_flag,
int *conf_state,
gss_iov_buffer_desc *iov,
int iov_count,
krb5_keyblock *key)
{
OM_uint32 major_status, junk;
gss_iov_buffer_desc *header, *padding, *trailer;
krb5_error_code kret;
int32_t seq_number;
u_char Klocaldata[16], k6_data[16], *p, *p0;
size_t make_len = 0;
size_t header_len = 0;
size_t data_len = 0;
krb5_keyblock Klocal;
int i;
header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
for (i = 0; i < iov_count; i++) {
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_DATA:
break;
default:
continue;
}
data_len += iov[i].buffer.length;
}
if (padding) {
data_len += 1;
}
if (IS_DCE_STYLE(ctx)) {
size_t unwrapped_len;
unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
_gssapi_encap_length(unwrapped_len,
&make_len,
&header_len,
GSS_KRB5_MECHANISM);
} else {
size_t unwrapped_len;
unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len;
_gssapi_encap_length(unwrapped_len,
&make_len,
&header_len,
GSS_KRB5_MECHANISM);
header_len -= data_len;
}
if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
major_status = _gk_allocate_buffer(minor_status, header,
header_len);
if (major_status != GSS_S_COMPLETE)
goto failure;
} else if (header->buffer.length < header_len) {
*minor_status = KRB5_BAD_MSIZE;
major_status = GSS_S_FAILURE;
goto failure;
} else {
header->buffer.length = header_len;
}
if (padding) {
if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
major_status = _gk_allocate_buffer(minor_status, padding, 1);
if (major_status != GSS_S_COMPLETE)
goto failure;
} else if (padding->buffer.length < 1) {
*minor_status = KRB5_BAD_MSIZE;
major_status = GSS_S_FAILURE;
goto failure;
} else {
padding->buffer.length = 1;
}
memset(padding->buffer.value, 1, 1);
}
if (trailer) {
trailer->buffer.length = 0;
trailer->buffer.value = NULL;
}
p0 = _gssapi_make_mech_header(header->buffer.value,
make_len,
GSS_KRB5_MECHANISM);
p = p0;
*p++ = 0x02; /* TOK_ID */
*p++ = 0x01;
*p++ = 0x11; /* SGN_ALG */
*p++ = 0x00;
if (conf_req_flag) {
*p++ = 0x10; /* SEAL_ALG */
*p++ = 0x00;
} else {
*p++ = 0xff; /* SEAL_ALG */
*p++ = 0xff;
}
*p++ = 0xff; /* Filler */
*p++ = 0xff;
p = NULL;
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
krb5_auth_con_getlocalseqnumber(context,
ctx->auth_context,
&seq_number);
_gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
krb5_auth_con_setlocalseqnumber(context,
ctx->auth_context,
++seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
memset(p0 + 8 + 4,
(ctx->more_flags & LOCAL) ? 0 : 0xff,
4);
krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
/* Sign Data */
kret = arcfour_mic_cksum_iov(context,
key, KRB5_KU_USAGE_SEAL,
p0 + 16, 8, /* SGN_CKSUM */
p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
p0 + 24, 8, /* Confounder */
iov, iov_count, /* Data + SignOnly */
padding); /* padding */
if (kret) {
*minor_status = kret;
major_status = GSS_S_FAILURE;
goto failure;
}
Klocal.keytype = key->keytype;
Klocal.keyvalue.data = Klocaldata;
Klocal.keyvalue.length = sizeof(Klocaldata);
for (i = 0; i < 16; i++) {
Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
}
kret = arcfour_mic_key(context, &Klocal,
p0 + 8, 4, /* SND_SEQ */
k6_data, sizeof(k6_data));
memset(Klocaldata, 0, sizeof(Klocaldata));
if (kret) {
*minor_status = kret;
major_status = GSS_S_FAILURE;
goto failure;
}
if (conf_req_flag) {
EVP_CIPHER_CTX rc4_key;
EVP_CIPHER_CTX_init(&rc4_key);
EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
/* Confounder */
EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8);
/* Seal Data */
for (i=0; i < iov_count; i++) {
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_DATA:
break;
default:
continue;
}
EVP_Cipher(&rc4_key, iov[i].buffer.value,
iov[i].buffer.value, iov[i].buffer.length);
}
/* Padding */
if (padding) {
EVP_Cipher(&rc4_key, padding->buffer.value,
padding->buffer.value, padding->buffer.length);
}
EVP_CIPHER_CTX_cleanup(&rc4_key);
}
memset(k6_data, 0, sizeof(k6_data));
kret = arcfour_mic_key(context, key,
p0 + 16, 8, /* SGN_CKSUM */
k6_data, sizeof(k6_data));
if (kret) {
*minor_status = kret;
major_status = GSS_S_FAILURE;
}
{
EVP_CIPHER_CTX rc4_key;
EVP_CIPHER_CTX_init(&rc4_key);
EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */
EVP_CIPHER_CTX_cleanup(&rc4_key);
memset(k6_data, 0, sizeof(k6_data));
}
if (conf_state)
*conf_state = conf_req_flag;
*minor_status = 0;
return GSS_S_COMPLETE;
failure:
gss_release_iov_buffer(&junk, iov, iov_count);
return major_status;
}
OM_uint32
_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
gsskrb5_ctx ctx,
krb5_context context,
int *pconf_state,
gss_qop_t *pqop_state,
gss_iov_buffer_desc *iov,
int iov_count,
krb5_keyblock *key)
{
OM_uint32 major_status;
gss_iov_buffer_desc *header, *padding, *trailer;
krb5_keyblock Klocal;
uint8_t Klocaldata[16];
uint8_t k6_data[16], snd_seq[8], Confounder[8];
uint8_t cksum_data[8];
uint8_t *_p = NULL;
const uint8_t *p, *p0;
size_t verify_len = 0;
uint32_t seq_number;
size_t hlen = 0;
int conf_state;
int cmp;
size_t i;
krb5_error_code kret;
OM_uint32 ret;
if (pconf_state != NULL) {
*pconf_state = 0;
}
if (pqop_state != NULL) {
*pqop_state = 0;
}
header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
/* Check if the packet is correct */
major_status = _gk_verify_buffers(minor_status,
ctx,
header,
padding,
trailer);
if (major_status != GSS_S_COMPLETE) {
return major_status;
}
if (padding != NULL && padding->buffer.length != 1) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
if (IS_DCE_STYLE(context)) {
verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
if (header->buffer.length > verify_len) {
return GSS_S_BAD_MECH;
}
} else {
verify_len = header->buffer.length;
}
_p = header->buffer.value;
ret = _gssapi_verify_mech_header(&_p,
verify_len,
GSS_KRB5_MECHANISM);
if (ret) {
return ret;
}
p0 = _p;
/* length of mech header */
hlen = (p0 - (uint8_t *)header->buffer.value);
hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE;
if (hlen > header->buffer.length) {
return GSS_S_BAD_MECH;
}
p = p0;
if (memcmp(p, "\x02\x01", 2) != 0)
return GSS_S_BAD_SIG;
p += 2;
if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
return GSS_S_BAD_SIG;
p += 2;
if (memcmp (p, "\x10\x00", 2) == 0)
conf_state = 1;
else if (memcmp (p, "\xff\xff", 2) == 0)
conf_state = 0;
else
return GSS_S_BAD_SIG;
p += 2;
if (memcmp (p, "\xff\xff", 2) != 0)
return GSS_S_BAD_MIC;
p = NULL;
kret = arcfour_mic_key(context,
key,
p0 + 16, /* SGN_CKSUM */
8, /* SGN_CKSUM_LEN */
k6_data,
sizeof(k6_data));
if (kret) {
*minor_status = kret;
return GSS_S_FAILURE;
}
{
EVP_CIPHER_CTX rc4_key;
EVP_CIPHER_CTX_init(&rc4_key);
EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */
EVP_CIPHER_CTX_cleanup(&rc4_key);
memset(k6_data, 0, sizeof(k6_data));
}
_gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
if (ctx->more_flags & LOCAL) {
cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
} else {
cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
}
if (cmp != 0) {
*minor_status = 0;
return GSS_S_BAD_MIC;
}
if (ctx->more_flags & LOCAL) {
cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
} else {
cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
}
if (cmp != 0) {
*minor_status = 0;
return GSS_S_BAD_MIC;
}
/* keyblock */
Klocal.keytype = key->keytype;
Klocal.keyvalue.data = Klocaldata;
Klocal.keyvalue.length = sizeof(Klocaldata);
for (i = 0; i < 16; i++) {
Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
}
kret = arcfour_mic_key(context,
&Klocal,
snd_seq,
4,
k6_data, sizeof(k6_data));
memset(Klocaldata, 0, sizeof(Klocaldata));
if (kret) {
*minor_status = kret;
return GSS_S_FAILURE;
}
if (conf_state == 1) {
EVP_CIPHER_CTX rc4_key;
EVP_CIPHER_CTX_init(&rc4_key);
EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
/* Confounder */
EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8);
/* Data */
for (i = 0; i < iov_count; i++) {
switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
case GSS_IOV_BUFFER_TYPE_DATA:
break;
default:
continue;
}
EVP_Cipher(&rc4_key, iov[i].buffer.value,
iov[i].buffer.value, iov[i].buffer.length);
}
/* Padding */
if (padding) {
EVP_Cipher(&rc4_key, padding->buffer.value,
padding->buffer.value, padding->buffer.length);
}
EVP_CIPHER_CTX_cleanup(&rc4_key);
} else {
/* Confounder */
memcpy(Confounder, p0 + 24, 8);
}
memset(k6_data, 0, sizeof(k6_data));
/* Prepare the buffer for signing */
kret = arcfour_mic_cksum_iov(context,
key, KRB5_KU_USAGE_SEAL,
cksum_data, sizeof(cksum_data),
p0, 8,
Confounder, sizeof(Confounder),
iov, iov_count,
padding);
if (kret) {
*minor_status = kret;
return GSS_S_FAILURE;
}
cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
if (cmp != 0) {
*minor_status = 0;
return GSS_S_BAD_MIC;
}
if (padding) {
size_t plen;
ret = _gssapi_verify_pad(&padding->buffer, 1, &plen);
if (ret) {
*minor_status = 0;
return ret;
}
}
HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
ret = _gssapi_msg_order_check(ctx->order, seq_number);
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
if (ret != 0) {
return ret;
}
if (pconf_state) {
*pconf_state = conf_state;
}
*minor_status = 0;
return GSS_S_COMPLETE;
}

View File

@@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token,
size_t padlength;
int i;
if (wrapped_token->length < 1)
return GSS_S_BAD_MECH;
pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
padlength = *pad;

View File

@@ -28,5 +28,6 @@ error_code NO_WRITE_SUPPORT, "HDB backend doesn't contain write support"
error_code NOT_FOUND_HERE, "The secret for this entry is not replicated to this database"
error_code MISUSE, "Incorrect use of the API"
error_code KVNO_NOT_FOUND, "Entry key version number not found"
error_code WRONG_REALM, "The principal exists in another realm."
end

View File

@@ -2330,6 +2330,17 @@ krb5_init_creds_step(krb5_context context,
ret = krb5_principal_set_realm(context,
ctx->cred.client,
*ctx->error.crealm);
if (ret)
goto out;
if (krb5_principal_is_krbtgt(context, ctx->cred.server)) {
ret = krb5_init_creds_set_service(context, ctx, NULL);
if (ret)
goto out;
}
free_AS_REQ(&ctx->as_req);
memset(&ctx->as_req, 0, sizeof(ctx->as_req));
ctx->used_pa_types = 0;
} else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 && ctx->prompter) {
@@ -2379,6 +2390,15 @@ krb5_init_creds_step(krb5_context context,
}
}
if (ctx->as_req.req_body.cname == NULL) {
ret = init_as_req(context, ctx->flags, &ctx->cred,
ctx->addrs, ctx->etypes, &ctx->as_req);
if (ret) {
free_init_creds_ctx(context, ctx);
return ret;
}
}
if (ctx->as_req.padata) {
free_METHOD_DATA(ctx->as_req.padata);
free(ctx->as_req.padata);

View File

@@ -440,6 +440,7 @@ EXPORTS
krb5_make_principal
krb5_max_sockaddr_size
krb5_mk_error
krb5_mk_error_ext
krb5_mk_priv
krb5_mk_rep
krb5_mk_req

View File

@@ -34,15 +34,16 @@
#include "krb5_locl.h"
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_mk_error(krb5_context context,
krb5_error_code error_code,
const char *e_text,
const krb5_data *e_data,
const krb5_principal client,
const krb5_principal server,
time_t *client_time,
int *client_usec,
krb5_data *reply)
krb5_mk_error_ext(krb5_context context,
krb5_error_code error_code,
const char *e_text,
const krb5_data *e_data,
const krb5_principal server,
const PrincipalName *client_name,
const Realm *client_realm,
time_t *client_time,
int *client_usec,
krb5_data *reply)
{
const char *e_text2 = NULL;
KRB_ERROR msg;
@@ -78,10 +79,8 @@ krb5_mk_error(krb5_context context,
static char unspec[] = "<unspecified realm>";
msg.realm = unspec;
}
if(client){
msg.crealm = &client->realm;
msg.cname = &client->name;
}
msg.crealm = rk_UNCONST(client_realm);
msg.cname = rk_UNCONST(client_name);
ASN1_MALLOC_ENCODE(KRB_ERROR, reply->data, reply->length, &msg, &len, ret);
if (e_text2)
@@ -92,3 +91,27 @@ krb5_mk_error(krb5_context context,
krb5_abortx(context, "internal error in ASN.1 encoder");
return 0;
}
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_mk_error(krb5_context context,
krb5_error_code error_code,
const char *e_text,
const krb5_data *e_data,
const krb5_principal client,
const krb5_principal server,
time_t *client_time,
int *client_usec,
krb5_data *reply)
{
const PrincipalName *client_name = NULL;
const Realm *client_realm = NULL;
if (client) {
client_realm = &client->realm;
client_name = &client->name;
}
return krb5_mk_error_ext(context, error_code, e_text, e_data,
server, client_name, client_realm,
client_time, client_usec, reply);
}

View File

@@ -595,11 +595,12 @@ verify_logonname(krb5_context context,
krb5_const_principal principal)
{
krb5_error_code ret;
krb5_principal p2;
uint32_t time1, time2;
krb5_storage *sp;
uint16_t len;
char *s;
char *s = NULL;
char *principal_string = NULL;
char *logon_string = NULL;
sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
logon_name->buffersize);
@@ -670,31 +671,36 @@ verify_logonname(krb5_context context,
return ret;
}
u8len += 1; /* Add space for NUL */
s = malloc(u8len);
if (s == NULL) {
logon_string = malloc(u8len);
if (logon_string == NULL) {
free(ucs2);
return krb5_enomem(context);
}
ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
free(ucs2);
if (ret) {
free(s);
free(logon_string);
krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
return ret;
}
}
ret = krb5_parse_name_flags(context, s,
KRB5_PRINCIPAL_PARSE_NO_REALM |
KRB5_PRINCIPAL_PARSE_ENTERPRISE, &p2);
free(s);
if (ret)
ret = krb5_unparse_name_flags(context, principal,
KRB5_PRINCIPAL_UNPARSE_NO_REALM |
KRB5_PRINCIPAL_UNPARSE_DISPLAY,
&principal_string);
if (ret) {
free(logon_string);
return ret;
if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
ret = EINVAL;
krb5_set_error_message(context, ret, "PAC logon name mismatch");
}
krb5_free_principal(context, p2);
ret = strcmp(logon_string, principal_string);
if (ret != 0) {
ret = EINVAL;
krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]",
logon_string, principal_string);
}
free(logon_string);
free(principal_string);
return ret;
out:
return ret;

View File

@@ -433,6 +433,7 @@ HEIMDAL_KRB5_2.0 {
krb5_make_principal;
krb5_max_sockaddr_size;
krb5_mk_error;
krb5_mk_error_ext;
krb5_mk_priv;
krb5_mk_rep;
krb5_mk_req;

View File

@@ -23,6 +23,7 @@ $(libheimntlm_la_OBJECTS): $(srcdir)/version-script.map
libheimntlm_la_LIBADD = \
../krb5/libkrb5.la \
$(top_builddir)/lib/wind/libwind.la \
$(LIB_hcrypto) \
$(LIBADD_roken)