#include "k5-int.h"
static krb5_error_code
krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
{
krb5_error_code retval;
krb5_checksum checksum;
krb5_authenticator authent;
krb5_ap_req request;
krb5_data * scratch;
krb5_data * toutbuf;
if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
&in_cred->keyblock,
KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
in_data, &checksum))) {
free(checksum.contents);
return(retval);
}
authent.subkey = 0;
authent.seq_number = 0;
authent.checksum = &checksum;
authent.client = in_cred->client;
authent.authorization_data = in_cred->authdata;
if ((retval = krb5_us_timeofday(context, &authent.ctime,
&authent.cusec))) {
free(checksum.contents);
return(retval);
}
if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
free(checksum.contents);
return(retval);
}
free(checksum.contents);
request.authenticator.ciphertext.data = 0;
request.authenticator.kvno = 0;
request.ap_options = 0;
request.ticket = 0;
if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
goto cleanup_data;
if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
KRB5_KEYUSAGE_TGS_REQ_AUTH,
scratch, &request.authenticator)))
goto cleanup_ticket;
retval = encode_krb5_ap_req(&request, &toutbuf);
*outbuf = *toutbuf;
krb5_xfree(toutbuf);
memset(request.authenticator.ciphertext.data, 0,
request.authenticator.ciphertext.length);
free(request.authenticator.ciphertext.data);
cleanup_ticket:
krb5_free_ticket(context, request.ticket);
cleanup_data:
memset(scratch->data, 0, scratch->length);
free(scratch->data);
free(scratch);
return retval;
}
krb5_error_code
krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
krb5_const_principal sname, krb5_address *const *addrs,
krb5_authdata *const *authorization_data,
krb5_pa_data *const *padata, const krb5_data *second_ticket,
krb5_creds *in_cred, krb5_response *rep)
{
krb5_error_code retval;
krb5_kdc_req tgsreq;
krb5_data *scratch, scratch2;
krb5_ticket *sec_ticket = 0;
krb5_ticket *sec_ticket_arr[2];
krb5_timestamp time_now;
krb5_pa_data **combined_padata;
krb5_pa_data ap_req_padata;
int tcp_only = 0, use_master;
if (!in_cred->ticket.length)
return(KRB5_NO_TKT_SUPPLIED);
memset((char *)&tgsreq, 0, sizeof(tgsreq));
tgsreq.kdc_options = kdcoptions;
tgsreq.server = (krb5_principal) sname;
tgsreq.from = timestruct->starttime;
tgsreq.till = timestruct->endtime ? timestruct->endtime :
in_cred->times.endtime;
tgsreq.rtime = timestruct->renew_till;
if ((retval = krb5_timeofday(context, &time_now)))
return(retval);
rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now;
rep->request_time = time_now;
tgsreq.addresses = (krb5_address **) addrs;
if (authorization_data) {
if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data,
&scratch)))
return(retval);
if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
scratch,
&tgsreq.authorization_data))) {
krb5_xfree(tgsreq.authorization_data.ciphertext.data);
krb5_free_data(context, scratch);
return retval;
}
krb5_free_data(context, scratch);
}
if (ktypes) {
for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
return KRB5_PROG_ETYPE_NOSUPP;
}
tgsreq.ktype = (krb5_enctype *)ktypes;
} else {
krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype));
for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
}
if (second_ticket) {
if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
goto send_tgs_error_1;
sec_ticket_arr[0] = sec_ticket;
sec_ticket_arr[1] = 0;
tgsreq.second_ticket = sec_ticket_arr;
} else
tgsreq.second_ticket = 0;
if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
goto send_tgs_error_2;
if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
krb5_free_data(context, scratch);
goto send_tgs_error_2;
}
krb5_free_data(context, scratch);
ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
ap_req_padata.length = scratch2.length;
ap_req_padata.contents = (krb5_octet *)scratch2.data;
if (padata) {
krb5_pa_data * const * counter;
register unsigned int i = 0;
for (counter = padata; *counter; counter++, i++);
combined_padata = malloc((i+2) * sizeof(*combined_padata));
if (!combined_padata) {
krb5_xfree(ap_req_padata.contents);
retval = ENOMEM;
goto send_tgs_error_2;
}
combined_padata[0] = &ap_req_padata;
for (i = 1, counter = padata; *counter; counter++, i++)
combined_padata[i] = (krb5_pa_data *) *counter;
combined_padata[i] = 0;
} else {
combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
if (!combined_padata) {
krb5_xfree(ap_req_padata.contents);
retval = ENOMEM;
goto send_tgs_error_2;
}
combined_padata[0] = &ap_req_padata;
combined_padata[1] = 0;
}
tgsreq.padata = combined_padata;
if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
krb5_xfree(ap_req_padata.contents);
krb5_xfree(combined_padata);
goto send_tgs_error_2;
}
krb5_xfree(ap_req_padata.contents);
krb5_xfree(combined_padata);
send_again:
use_master = 0;
retval = krb5_sendto_kdc(context, scratch,
krb5_princ_realm(context, sname),
&rep->response, &use_master, tcp_only);
if (retval == 0) {
if (krb5_is_krb_error(&rep->response)) {
if (!tcp_only) {
krb5_error *err_reply;
retval = decode_krb5_error(&rep->response, &err_reply);
if (retval)
goto send_tgs_error_3;
if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
tcp_only = 1;
krb5_free_error(context, err_reply);
free(rep->response.data);
rep->response.data = 0;
goto send_again;
}
krb5_free_error(context, err_reply);
send_tgs_error_3:
;
}
rep->message_type = KRB5_ERROR;
} else if (krb5_is_tgs_rep(&rep->response))
rep->message_type = KRB5_TGS_REP;
else
rep->message_type = KRB5_ERROR;
}
krb5_free_data(context, scratch);
send_tgs_error_2:;
if (sec_ticket)
krb5_free_ticket(context, sec_ticket);
send_tgs_error_1:;
if (ktypes == NULL)
krb5_xfree(tgsreq.ktype);
if (tgsreq.authorization_data.ciphertext.data) {
memset(tgsreq.authorization_data.ciphertext.data, 0,
tgsreq.authorization_data.ciphertext.length);
krb5_xfree(tgsreq.authorization_data.ciphertext.data);
}
return retval;
}