2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A
2N/A/*
2N/A * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include "k5-int.h"
2N/A#include "cleanup.h"
2N/A#include "auth_con.h"
2N/A
2N/A#include <stddef.h> /* NULL */
2N/A#include <stdlib.h> /* malloc */
2N/A#include <errno.h> /* ENOMEM */
2N/A
2N/A/* Solaris Kerberos */
2N/A#include "kerberos_dtrace.h"
2N/A
2N/A/*-------------------- decrypt_credencdata --------------------*/
2N/A
2N/A/*
2N/A * decrypt the enc_part of a krb5_cred
2N/A */
2N/Astatic krb5_error_code
2N/Adecrypt_credencdata(krb5_context context, krb5_cred *pcred,
2N/A krb5_key pkey, krb5_cred_enc_part *pcredenc)
2N/A{
2N/A krb5_cred_enc_part * ppart = NULL;
2N/A krb5_error_code retval;
2N/A krb5_data scratch;
2N/A
2N/A scratch.length = pcred->enc_part.ciphertext.length;
2N/A if (!(scratch.data = (char *)malloc(scratch.length)))
2N/A return ENOMEM;
2N/A
2N/A if (pkey != NULL) {
2N/A if ((retval = krb5_k_decrypt(context, pkey,
2N/A KRB5_KEYUSAGE_KRB_CRED_ENCPART, 0,
2N/A &pcred->enc_part, &scratch)))
2N/A goto cleanup;
2N/A } else {
2N/A memcpy(scratch.data, pcred->enc_part.ciphertext.data, scratch.length);
2N/A }
2N/A
2N/A /* now decode the decrypted stuff */
2N/A if ((retval = decode_krb5_enc_cred_part(&scratch, &ppart)))
2N/A goto cleanup;
2N/A
2N/A *pcredenc = *ppart;
2N/A retval = 0;
2N/A
2N/Acleanup:
2N/A if (ppart != NULL) {
2N/A memset(ppart, 0, sizeof(*ppart));
2N/A free(ppart);
2N/A }
2N/A memset(scratch.data, 0, scratch.length);
2N/A free(scratch.data);
2N/A
2N/A return retval;
2N/A}
2N/A/*----------------------- krb5_rd_cred_basic -----------------------*/
2N/A
2N/Astatic krb5_error_code
2N/Akrb5_rd_cred_basic(krb5_context context, krb5_data *pcreddata,
2N/A krb5_key pkey, krb5_replay_data *replaydata,
2N/A krb5_creds ***pppcreds)
2N/A{
2N/A krb5_error_code retval;
2N/A krb5_cred * pcred;
2N/A krb5_int32 ncreds;
2N/A krb5_int32 i = 0;
2N/A krb5_cred_enc_part encpart;
2N/A
2N/A /* decode cred message */
2N/A if ((retval = decode_krb5_cred(pcreddata, &pcred))) {
2N/A /* Solaris Kerberos */
2N/A KERBEROS_PROBE_KRB_CRED(READ, pcreddata, pcred, NULL);
2N/A return retval;
2N/A }
2N/A
2N/A memset(&encpart, 0, sizeof(encpart));
2N/A
2N/A if ((retval = decrypt_credencdata(context, pcred, pkey, &encpart)))
2N/A goto cleanup_cred;
2N/A
2N/A /* Solaris Kerberos */
2N/A KERBEROS_PROBE_KRB_CRED(READ, pcreddata, pcred, &encpart);
2N/A
2N/A replaydata->timestamp = encpart.timestamp;
2N/A replaydata->usec = encpart.usec;
2N/A replaydata->seq = encpart.nonce;
2N/A
2N/A /*
2N/A * Allocate the list of creds. The memory is allocated so that
2N/A * krb5_free_tgt_creds can be used to free the list.
2N/A */
2N/A for (ncreds = 0; pcred->tickets[ncreds]; ncreds++);
2N/A
2N/A if ((*pppcreds =
2N/A (krb5_creds **)malloc((size_t)(sizeof(krb5_creds *) *
2N/A (ncreds + 1)))) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup_cred;
2N/A }
2N/A (*pppcreds)[0] = NULL;
2N/A
2N/A /*
2N/A * For each credential, create a strcture in the list of
2N/A * credentials and copy the information.
2N/A */
2N/A while (i < ncreds) {
2N/A krb5_cred_info * pinfo;
2N/A krb5_creds * pcur;
2N/A krb5_data * pdata;
2N/A
2N/A if ((pcur = (krb5_creds *)calloc(1, sizeof(krb5_creds))) == NULL) {
2N/A retval = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A (*pppcreds)[i] = pcur;
2N/A (*pppcreds)[i+1] = 0;
2N/A pinfo = encpart.ticket_info[i++];
2N/A
2N/A if ((retval = krb5_copy_principal(context, pinfo->client,
2N/A &pcur->client)))
2N/A goto cleanup;
2N/A
2N/A if ((retval = krb5_copy_principal(context, pinfo->server,
2N/A &pcur->server)))
2N/A goto cleanup;
2N/A
2N/A if ((retval = krb5_copy_keyblock_contents(context, pinfo->session,
2N/A &pcur->keyblock)))
2N/A goto cleanup;
2N/A
2N/A if ((retval = krb5_copy_addresses(context, pinfo->caddrs,
2N/A &pcur->addresses)))
2N/A goto cleanup;
2N/A
2N/A if ((retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)))
2N/A goto cleanup;
2N/A
2N/A pcur->ticket = *pdata;
2N/A free(pdata);
2N/A
2N/A
2N/A pcur->is_skey = FALSE;
2N/A pcur->magic = KV5M_CREDS;
2N/A pcur->times = pinfo->times;
2N/A pcur->ticket_flags = pinfo->flags;
2N/A pcur->authdata = NULL; /* not used */
2N/A memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket));
2N/A }
2N/A
2N/A /*
2N/A * NULL terminate the list
2N/A */
2N/A (*pppcreds)[i] = NULL;
2N/A
2N/Acleanup:
2N/A if (retval) {
2N/A krb5_free_tgt_creds(context, *pppcreds);
2N/A /* Solaris Kerberos */
2N/A *pppcreds = NULL;
2N/A }
2N/A
2N/Acleanup_cred:
2N/A krb5_free_cred(context, pcred);
2N/A krb5_free_cred_enc_part(context, &encpart);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/*----------------------- krb5_rd_cred -----------------------*/
2N/A
2N/A/*
2N/A * This functions takes as input an KRB_CRED message, validates it, and
2N/A * outputs the nonce and an array of the forwarded credentials.
2N/A */
2N/Akrb5_error_code KRB5_CALLCONV
2N/Akrb5_rd_cred(krb5_context context, krb5_auth_context auth_context,
2N/A krb5_data *pcreddata, krb5_creds ***pppcreds,
2N/A krb5_replay_data *outdata)
2N/A{
2N/A krb5_error_code retval;
2N/A krb5_key key;
2N/A krb5_replay_data replaydata;
2N/A
2N/A /* Get key */
2N/A if ((key = auth_context->recv_subkey) == NULL)
2N/A key = auth_context->key;
2N/A
2N/A if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
2N/A (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) &&
2N/A (outdata == NULL))
2N/A /* Need a better error */
2N/A return KRB5_RC_REQUIRED;
2N/A
2N/A if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) &&
2N/A (auth_context->rcache == NULL))
2N/A return KRB5_RC_REQUIRED;
2N/A
2N/A
2N/A /*
2N/A * If decrypting with the first key we try fails, perhaps the
2N/A * credentials are stored in the session key so try decrypting with
2N/A * that.
2N/A */
2N/A if ((retval = krb5_rd_cred_basic(context, pcreddata, key,
2N/A &replaydata, pppcreds))) {
2N/A if ((retval = krb5_rd_cred_basic(context, pcreddata,
2N/A auth_context->key,
2N/A &replaydata, pppcreds))) {
2N/A return retval;
2N/A }
2N/A }
2N/A
2N/A if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) {
2N/A krb5_donot_replay replay;
2N/A
2N/A if ((retval = krb5int_check_clockskew(context, replaydata.timestamp)))
2N/A goto error;
2N/A
2N/A if ((retval = krb5_gen_replay_name(context, auth_context->remote_addr,
2N/A "_forw", &replay.client)))
2N/A goto error;
2N/A
2N/A replay.server = ""; /* XXX */
2N/A replay.msghash = NULL;
2N/A replay.cusec = replaydata.usec;
2N/A replay.ctime = replaydata.timestamp;
2N/A if ((retval = krb5_rc_store(context, auth_context->rcache, &replay))) {
2N/A free(replay.client);
2N/A goto error;
2N/A }
2N/A free(replay.client);
2N/A }
2N/A
2N/A if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) {
2N/A if (auth_context->remote_seq_number != replaydata.seq) {
2N/A retval = KRB5KRB_AP_ERR_BADORDER;
2N/A goto error;
2N/A }
2N/A auth_context->remote_seq_number++;
2N/A }
2N/A
2N/A if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) ||
2N/A (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) {
2N/A outdata->timestamp = replaydata.timestamp;
2N/A outdata->usec = replaydata.usec;
2N/A outdata->seq = replaydata.seq;
2N/A }
2N/A
2N/Aerror:;
2N/A if (retval) {
2N/A krb5_free_tgt_creds(context, *pppcreds);
2N/A *pppcreds = NULL;
2N/A }
2N/A return retval;
2N/A}