#include "k5-int.h"
#include "int-proto.h"
#include "auth_con.h"
static krb5_error_code
decrypt_encpart(krb5_context context, krb5_enc_data *ctext,
krb5_auth_context authcon, krb5_cred_enc_part **encpart_out)
{
krb5_error_code ret;
krb5_data plain = empty_data();
krb5_boolean decrypted = FALSE;
*encpart_out = NULL;
if (authcon->recv_subkey == NULL && authcon->key == NULL)
return decode_krb5_enc_cred_part(&ctext->ciphertext, encpart_out);
ret = alloc_data(&plain, ctext->ciphertext.length);
if (ret)
return ret;
if (authcon->recv_subkey != NULL) {
ret = krb5_k_decrypt(context, authcon->recv_subkey,
KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
decrypted = (ret == 0);
}
if (!decrypted && authcon->key != NULL) {
ret = krb5_k_decrypt(context, authcon->key,
KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0, ctext, &plain);
decrypted = (ret == 0);
}
if (decrypted)
ret = decode_krb5_enc_cred_part(&plain, encpart_out);
zapfree(plain.data, plain.length);
return ret;
}
static krb5_error_code
make_cred_list(krb5_context context, krb5_cred *krbcred,
krb5_cred_enc_part *encpart, krb5_creds ***creds_out)
{
krb5_error_code ret = 0;
krb5_creds **list = NULL;
krb5_cred_info *info;
krb5_data *ticket_data;
size_t i, count;
*creds_out = NULL;
for (count = 0; krbcred->tickets[count] != NULL; count++);
list = k5calloc(count + 1, sizeof(*list), &ret);
if (list == NULL)
goto cleanup;
for (i = 0; i < count; i++) {
list[i] = k5alloc(sizeof(*list[i]), &ret);
if (list[i] == NULL)
goto cleanup;
info = encpart->ticket_info[i];
ret = krb5_copy_principal(context, info->client, &list[i]->client);
if (ret)
goto cleanup;
ret = krb5_copy_principal(context, info->server, &list[i]->server);
if (ret)
goto cleanup;
ret = krb5_copy_keyblock_contents(context, info->session,
&list[i]->keyblock);
if (ret)
goto cleanup;
ret = krb5_copy_addresses(context, info->caddrs, &list[i]->addresses);
if (ret)
goto cleanup;
ret = encode_krb5_ticket(krbcred->tickets[i], &ticket_data);
if (ret)
goto cleanup;
list[i]->ticket = *ticket_data;
free(ticket_data);
list[i]->is_skey = FALSE;
list[i]->magic = KV5M_CREDS;
list[i]->times = info->times;
list[i]->ticket_flags = info->flags;
list[i]->authdata = NULL;
list[i]->second_ticket = empty_data();
}
*creds_out = list;
list = NULL;
cleanup:
krb5_free_tgt_creds(context, list);
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_rd_cred(krb5_context context, krb5_auth_context authcon,
krb5_data *creddata, krb5_creds ***creds_out,
krb5_replay_data *replaydata_out)
{
krb5_error_code ret = 0;
krb5_creds **credlist = NULL;
krb5_cred *krbcred = NULL;
krb5_cred_enc_part *encpart = NULL;
krb5_replay_data rdata;
const krb5_int32 flags = authcon->auth_context_flags;
*creds_out = NULL;
if (((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
(flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
replaydata_out == NULL)
return KRB5_RC_REQUIRED;
ret = decode_krb5_cred(creddata, &krbcred);
if (ret)
goto cleanup;
ret = decrypt_encpart(context, &krbcred->enc_part, authcon, &encpart);
if (ret)
goto cleanup;
ret = make_cred_list(context, krbcred, encpart, &credlist);
if (ret)
goto cleanup;
if (authcon->recv_subkey != NULL || authcon->key != NULL) {
rdata.timestamp = encpart->timestamp;
ret = k5_privsafe_check_replay(context, authcon, &rdata,
&krbcred->enc_part, NULL);
if (ret)
goto cleanup;
}
if (flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
if (authcon->remote_seq_number != (uint32_t)encpart->nonce) {
ret = KRB5KRB_AP_ERR_BADORDER;
goto cleanup;
}
authcon->remote_seq_number++;
}
*creds_out = credlist;
credlist = NULL;
if ((flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
(flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
replaydata_out->timestamp = encpart->timestamp;
replaydata_out->usec = encpart->usec;
replaydata_out->seq = encpart->nonce;
}
cleanup:
krb5_free_tgt_creds(context, credlist);
krb5_free_cred(context, krbcred);
krb5_free_cred_enc_part(context, encpart);
free(encpart);
return ret;
}