krb5 commit: Modernize send_tgs.c
Greg Hudson
ghudson at MIT.EDU
Sat Feb 9 18:44:45 EST 2013
https://github.com/krb5/krb5/commit/8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f
commit 8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f
Author: Greg Hudson <ghudson at mit.edu>
Date: Fri Feb 8 00:18:50 2013 -0500
Modernize send_tgs.c
Bring send_tgs.c up to date with current coding practices. No
functional changes.
src/lib/krb5/krb/send_tgs.c | 435 +++++++++++++++++++------------------------
1 files changed, 190 insertions(+), 245 deletions(-)
diff --git a/src/lib/krb5/krb/send_tgs.c b/src/lib/krb5/krb/send_tgs.c
index b215acf..89ac529 100644
--- a/src/lib/krb5/krb/send_tgs.c
+++ b/src/lib/krb5/krb/send_tgs.c
@@ -1,7 +1,7 @@
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* lib/krb5/krb/send_tgs.c */
+/* lib/krb5/krb/send_tgs.c - Construct a TGS request */
/*
- * Copyright 1990,1991,2009 by the Massachusetts Institute of Technology.
+ * Copyright 1990,1991,2009,2013 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
@@ -28,42 +28,28 @@
#include "int-proto.h"
#include "fast.h"
-/*
- Constructs a TGS request
- options is used for the options in the KRB_TGS_REQ.
- timestruct values are used for from, till, rtime " " "
- enctype is used for enctype " " ", and to encrypt the authorization data,
- sname is used for sname " " "
- addrs, if non-NULL, is used for addresses " " "
- authorization_dat, if non-NULL, is used for authorization_dat " " "
- second_ticket, if required by options, is used for the 2nd ticket in the req.
- in_cred is used for the ticket & session key in the KRB_AP_REQ header " " "
- (the KDC realm is extracted from in_cred->server's realm)
-
- The response is placed into *rep.
- rep->response.data is set to point at allocated storage which should be
- freed by the caller when finished.
-
- returns system errors
-*/
+/* Construct an AP-REQ message for a TGS request. */
static krb5_error_code
-tgs_construct_tgsreq(krb5_context context, krb5_data *in_data,
- krb5_creds *in_cred, krb5_data *outbuf, krb5_keyblock *subkey)
+tgs_construct_ap_req(krb5_context context, krb5_data *checksum_data,
+ krb5_creds *tgt, krb5_keyblock *subkey,
+ krb5_data **ap_req_asn1_out)
{
krb5_cksumtype cksumtype;
- krb5_error_code retval;
- krb5_checksum checksum;
- krb5_authenticator authent;
- krb5_ap_req request;
- krb5_data * scratch = NULL;
- krb5_data * toutbuf = NULL;
-
- checksum.contents = NULL;
- request.authenticator.ciphertext.data = NULL;
- request.authenticator.kvno = 0;
- request.ap_options = 0;
- request.ticket = 0;
- switch (in_cred->keyblock.enctype) {
+ krb5_error_code ret;
+ krb5_checksum checksum;
+ krb5_authenticator authent;
+ krb5_ap_req ap_req;
+ krb5_data *authent_asn1 = NULL;
+ krb5_ticket *ticket = NULL;
+ krb5_enc_data authent_enc;
+
+ *ap_req_asn1_out = NULL;
+ memset(&checksum, 0, sizeof(checksum));
+ memset(&ap_req, 0, sizeof(ap_req));
+ memset(&authent_enc, 0, sizeof(authent_enc));
+
+ /* Determine the authenticator checksum type. */
+ switch (tgt->keyblock.enctype) {
case ENCTYPE_DES_CBC_CRC:
case ENCTYPE_DES_CBC_MD4:
case ENCTYPE_DES_CBC_MD5:
@@ -72,80 +58,61 @@ tgs_construct_tgsreq(krb5_context context, krb5_data *in_data,
cksumtype = context->kdc_req_sumtype;
break;
default:
- retval = krb5int_c_mandatory_cksumtype(context, in_cred->keyblock.enctype, &cksumtype);
- if (retval)
+ ret = krb5int_c_mandatory_cksumtype(context, tgt->keyblock.enctype,
+ &cksumtype);
+ if (ret)
goto cleanup;
}
- /* Generate checksum */
- if ((retval = krb5_c_make_checksum(context, cksumtype,
- &in_cred->keyblock,
- KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
- in_data, &checksum))) {
- free(checksum.contents);
+ /* Generate checksum. */
+ ret = krb5_c_make_checksum(context, cksumtype, &tgt->keyblock,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, checksum_data,
+ &checksum);
+ if (ret)
goto cleanup;
- }
- /* gen authenticator */
- authent.subkey = subkey; /*owned by caller*/
+ /* Construct, encode, and encrypt an authenticator. */
+ authent.subkey = subkey;
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)))
+ authent.client = tgt->client;
+ authent.authorization_data = tgt->authdata;
+ ret = krb5_us_timeofday(context, &authent.ctime, &authent.cusec);
+ if (ret)
goto cleanup;
-
-
- /* encode the authenticator */
- if ((retval = encode_krb5_authenticator(&authent, &scratch)))
+ ret = encode_krb5_authenticator(&authent, &authent_asn1);
+ if (ret)
goto cleanup;
-
- free(checksum.contents);
- checksum.contents = NULL;
-
-
- if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
- /* Cleanup scratch and scratch data */
+ ret = krb5_encrypt_helper(context, &tgt->keyblock,
+ KRB5_KEYUSAGE_TGS_REQ_AUTH, authent_asn1,
+ &authent_enc);
+ if (ret)
goto cleanup;
- /* call the encryption routine */
- if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
- KRB5_KEYUSAGE_TGS_REQ_AUTH,
- scratch, &request.authenticator)))
+ ret = decode_krb5_ticket(&tgt->ticket, &ticket);
+ if (ret)
goto cleanup;
- if (!(retval = encode_krb5_ap_req(&request, &toutbuf))) {
- *outbuf = *toutbuf;
- free(toutbuf);
- }
-
- memset(request.authenticator.ciphertext.data, 0,
- request.authenticator.ciphertext.length);
- free(request.authenticator.ciphertext.data);
- request.authenticator.ciphertext.length = 0;
- request.authenticator.ciphertext.data = 0;
-
+ /* Encode the AP-REQ. */
+ ap_req.authenticator = authent_enc;
+ ap_req.ticket = ticket;
+ ret = encode_krb5_ap_req(&ap_req, ap_req_asn1_out);
cleanup:
- if (request.ticket)
- krb5_free_ticket(context, request.ticket);
-
- if (scratch != NULL && scratch->data != NULL) {
- zap(scratch->data, scratch->length);
- free(scratch->data);
- }
- free(scratch);
-
- return retval;
+ free(checksum.contents);
+ krb5_free_ticket(context, ticket);
+ krb5_free_data_contents(context, &authent_enc.ciphertext);
+ if (authent_asn1 != NULL)
+ zapfree(authent_asn1->data, authent_asn1->length);
+ free(authent_asn1);
+ return ret;
}
+
/*
- * Note that this function fills in part of rep even on failure.
- *
- * The pacb_fct callback allows the caller access to the nonce
- * and request subkey, for binding preauthentication data
+ * Construct a TGS request and return its ASN.1 encoding as well as the
+ * timestamp, nonce, and subkey used. The pacb_fn callback allows the caller
+ * to amend the request padata after the nonce and subkey are determined.
*/
-
krb5_error_code
krb5int_make_tgs_request_ext(krb5_context context,
struct krb5int_fast_request_state *fast_state,
@@ -155,198 +122,176 @@ krb5int_make_tgs_request_ext(krb5_context context,
krb5_const_principal sname,
krb5_address *const *addrs,
krb5_authdata *const *authorization_data,
- krb5_pa_data *const *padata,
+ krb5_pa_data *const *in_padata,
const krb5_data *second_ticket,
- krb5_creds *in_cred,
- krb5_error_code (*pacb_fct)(krb5_context,
- krb5_keyblock *,
- krb5_kdc_req *,
- void *),
+ krb5_creds *tgt,
+ krb5_error_code (*pacb_fn)(krb5_context,
+ krb5_keyblock *,
+ krb5_kdc_req *,
+ void *),
void *pacb_data,
- krb5_data *request_data,
- krb5_timestamp *timestamp,
- krb5_int32 *nonce,
- krb5_keyblock **subkey)
+ krb5_data *req_asn1_out,
+ krb5_timestamp *timestamp_out,
+ krb5_int32 *nonce_out,
+ krb5_keyblock **subkey_out)
{
- krb5_error_code retval;
- krb5_kdc_req tgsreq;
- krb5_data *scratch, scratch2 = empty_data();
+ krb5_error_code ret;
+ krb5_kdc_req req;
+ krb5_data *authdata_asn1 = NULL, *req_body_asn1 = NULL;
+ krb5_data *ap_req_asn1 = NULL, *tgs_req_asn1 = NULL;
krb5_ticket *sec_ticket = NULL;
krb5_ticket *sec_ticket_arr[2];
krb5_timestamp time_now;
- krb5_pa_data **combined_padata = NULL;
- krb5_keyblock *local_subkey = NULL;
-
- assert (subkey != NULL);
- *subkey = NULL;
-
- /*
- * in_creds MUST be a valid credential NOT just a partially filled in
- * place holder for us to get credentials for the caller.
- */
- if (!in_cred->ticket.length)
+ krb5_pa_data **padata = NULL, *pa;
+ krb5_keyblock *subkey = NULL;
+ krb5_enc_data authdata_enc;
+ krb5_enctype *defenctypes = NULL;
+ size_t count, i;
+
+ *req_asn1_out = empty_data();
+ *timestamp_out = 0;
+ *nonce_out = 0;
+ *subkey_out = NULL;
+ memset(&req, 0, sizeof(req));
+ memset(&authdata_enc, 0, sizeof(authdata_enc));
+
+ /* tgt must be an actual credential, not a template. */
+ if (!tgt->ticket.length)
return KRB5_NO_TKT_SUPPLIED;
- memset(&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.authorization_data.ciphertext.data = NULL;
- tgsreq.rtime = timestruct->renew_till;
- if ((retval = krb5_timeofday(context, &time_now)))
- return retval;
- /* XXX we know they are the same size... */
- *nonce = tgsreq.nonce = (krb5_int32)time_now;
- *timestamp = time_now;
-
- tgsreq.addresses = (krb5_address **) addrs;
-
- /* Generate subkey*/
- if ((retval = krb5_generate_subkey( context, &in_cred->keyblock,
- &local_subkey)) != 0)
- return retval;
- TRACE_SEND_TGS_SUBKEY(context, local_subkey);
-
- retval = krb5int_fast_tgs_armor(context, fast_state, local_subkey,
- &in_cred->keyblock, NULL, NULL);
- if (retval)
+ req.kdc_options = kdcoptions;
+ req.server = (krb5_principal)sname;
+ req.from = timestruct->starttime;
+ req.till = timestruct->endtime ? timestruct->endtime : tgt->times.endtime;
+ req.authorization_data.ciphertext.data = NULL;
+ req.rtime = timestruct->renew_till;
+ ret = krb5_timeofday(context, &time_now);
+ if (ret)
+ return ret;
+ *nonce_out = req.nonce = (krb5_int32)time_now;
+ *timestamp_out = time_now;
+
+ req.addresses = (krb5_address **)addrs;
+
+ /* Generate subkey. */
+ ret = krb5_generate_subkey(context, &tgt->keyblock, &subkey);
+ if (ret)
+ return ret;
+ TRACE_SEND_TGS_SUBKEY(context, subkey);
+
+ ret = krb5int_fast_tgs_armor(context, fast_state, subkey, &tgt->keyblock,
+ NULL, NULL);
+ if (ret)
goto cleanup;
- if (authorization_data) {
- /* need to encrypt it in the request */
- if ((retval = encode_krb5_authdata(authorization_data, &scratch)))
+ if (authorization_data != NULL) {
+ ret = encode_krb5_authdata(authorization_data, &authdata_asn1);
+ if (ret)
goto cleanup;
-
- retval = krb5_encrypt_helper(context, local_subkey,
- KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
- scratch, &tgsreq.authorization_data);
- krb5_free_data(context, scratch);
- if (retval)
+ ret = krb5_encrypt_helper(context, subkey,
+ KRB5_KEYUSAGE_TGS_REQ_AD_SUBKEY,
+ authdata_asn1, &authdata_enc);
+ if (ret)
goto cleanup;
+ req.authorization_data = authdata_enc;
}
- /* Get the encryption types list */
- if (ktypes) {
- /* Check passed ktypes and make sure they're valid. */
- for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
- if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes])) {
- retval = KRB5_PROG_ETYPE_NOSUPP;
+ /* Get the encryption types list. */
+ if (ktypes != NULL) {
+ /* Check passed enctypes and make sure they're valid. */
+ for (req.nktypes = 0; ktypes[req.nktypes]; req.nktypes++) {
+ if (!krb5_c_valid_enctype(ktypes[req.nktypes])) {
+ ret = KRB5_PROG_ETYPE_NOSUPP;
goto cleanup;
}
}
- tgsreq.ktype = (krb5_enctype *)ktypes;
+ req.ktype = (krb5_enctype *)ktypes;
} else {
- /* Get the default ktypes */
- krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype));
- for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
+ /* Get the default TGS enctypes. */
+ krb5_get_tgs_ktypes(context, sname, &defenctypes);
+ for (count = 0; defenctypes[count]; count++);
+ req.ktype = defenctypes;
+ req.nktypes = count;
}
- TRACE_SEND_TGS_ETYPES(context, tgsreq.ktype);
+ TRACE_SEND_TGS_ETYPES(context, req.ktype);
- if (second_ticket) {
- if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
+ if (second_ticket != NULL) {
+ ret = decode_krb5_ticket(second_ticket, &sec_ticket);
+ if (ret)
goto cleanup;
sec_ticket_arr[0] = sec_ticket;
- sec_ticket_arr[1] = 0;
- tgsreq.second_ticket = sec_ticket_arr;
- } else
- tgsreq.second_ticket = 0;
+ sec_ticket_arr[1] = NULL;
+ req.second_ticket = sec_ticket_arr;
+ }
- /* encode the body; then checksum it */
- retval = krb5int_fast_prep_req_body(context, fast_state, &tgsreq,
- &scratch);
- if (retval)
+ /* Encode the request body. */
+ ret = krb5int_fast_prep_req_body(context, fast_state, &req,
+ &req_body_asn1);
+ if (ret)
goto cleanup;
- /*
- * Get an ap_req.
- */
- if ((retval = tgs_construct_tgsreq(context, scratch, in_cred,
- &scratch2, local_subkey))) {
- krb5_free_data(context, scratch);
+ ret = tgs_construct_ap_req(context, req_body_asn1, tgt, subkey,
+ &ap_req_asn1);
+ if (ret)
goto cleanup;
- }
- krb5_free_data(context, scratch);
- tgsreq.padata = k5alloc(2 * sizeof(krb5_pa_data *), &retval);
- if (tgsreq.padata == NULL) {
- free(scratch2.data);
+ for (count = 0; in_padata != NULL && in_padata[count] != NULL; count++);
+
+ /* Construct a padata array for the request, beginning with the ap-req. */
+ padata = k5alloc((count + 2) * sizeof(krb5_pa_data *), &ret);
+ if (padata == NULL)
goto cleanup;
- }
- tgsreq.padata[0] = k5alloc(sizeof(krb5_pa_data), &retval);
- if (tgsreq.padata[0] == NULL) {
- free(scratch2.data);
+ padata[0] = k5alloc(sizeof(krb5_pa_data), &ret);
+ if (padata[0] == NULL)
goto cleanup;
- }
- tgsreq.padata[0]->pa_type = KRB5_PADATA_AP_REQ;
- tgsreq.padata[0]->length = scratch2.length;
- tgsreq.padata[0]->contents = (krb5_octet *)scratch2.data;
- tgsreq.padata[1] = NULL;
-
- /* combine in any other supplied padata, unfortunately now it is
- * necessary to copy it as the callback function might modify the
- * padata, and having a separate path for the non-callback case,
- * or attempting to determine which elements were changed by the
- * callback, would have complicated the code significantly.
- */
- if (padata) {
- krb5_pa_data **tmp;
- int i;
-
- for (i = 0; padata[i]; i++)
- ;
+ padata[0]->pa_type = KRB5_PADATA_AP_REQ;
+ padata[0]->contents = k5alloc(ap_req_asn1->length, &ret);
+ if (padata[0] == NULL)
+ goto cleanup;
+ memcpy(padata[0]->contents, ap_req_asn1->data, ap_req_asn1->length);
+ padata[0]->length = ap_req_asn1->length;
- tmp = realloc(tgsreq.padata, (i + 2) * sizeof(*combined_padata));
- if (tmp == NULL) {
- retval = ENOMEM;
+ /* Append copies of any other supplied padata. */
+ for (i = 0; in_padata != NULL && in_padata[i] != NULL; i++) {
+ pa = k5alloc(sizeof(krb5_pa_data), &ret);
+ if (pa == NULL)
goto cleanup;
- }
-
- tgsreq.padata = tmp;
-
- for (i = 0; padata[i]; i++) {
- krb5_pa_data *pa;
-
- pa = tgsreq.padata[1 + i] = k5alloc(sizeof(krb5_pa_data), &retval);
- if (tgsreq.padata == NULL)
- goto cleanup;
-
- pa->pa_type = padata[i]->pa_type;
- pa->length = padata[i]->length;
- pa->contents = k5alloc(padata[i]->length, &retval);
- if (pa->contents == NULL)
- goto cleanup;
- memcpy(pa->contents, padata[i]->contents, padata[i]->length);
- }
- tgsreq.padata[1 + i] = NULL;
+ pa->pa_type = in_padata[i]->pa_type;
+ pa->length = in_padata[i]->length;
+ pa->contents = k5alloc(in_padata[i]->length, &ret);
+ if (pa->contents == NULL)
+ goto cleanup;
+ memcpy(pa->contents, in_padata[i]->contents, in_padata[i]->length);
+ padata[i + 1] = pa;
}
+ req.padata = padata;
- if (pacb_fct != NULL) {
- if ((retval = (*pacb_fct)(context, local_subkey, &tgsreq, pacb_data)))
+ if (pacb_fn != NULL) {
+ ret = (*pacb_fn)(context, subkey, &req, pacb_data);
+ if (ret)
goto cleanup;
}
- /* the TGS_REQ is assembled in tgsreq, so encode it */
- retval = krb5int_fast_prep_req(context, fast_state, &tgsreq, &scratch2,
- encode_krb5_tgs_req, &scratch);
- if (retval)
- goto cleanup;
- *request_data = *scratch;
- free(scratch);
- scratch = NULL;
+ /* Encode the TGS-REQ. Discard the krb5_data container. */
+ ret = krb5int_fast_prep_req(context, fast_state, &req, ap_req_asn1,
+ encode_krb5_tgs_req, &tgs_req_asn1);
+ if (ret)
+ goto cleanup;
+ *req_asn1_out = *tgs_req_asn1;
+ free(tgs_req_asn1);
+ tgs_req_asn1 = NULL;
- *subkey = local_subkey;
- local_subkey = NULL;
+ *subkey_out = subkey;
+ subkey = NULL;
cleanup:
- krb5_free_pa_data(context, tgsreq.padata);
+ krb5_free_data(context, authdata_asn1);
+ krb5_free_data(context, req_body_asn1);
+ krb5_free_data(context, ap_req_asn1);
+ krb5_free_pa_data(context, req.padata);
krb5_free_ticket(context, sec_ticket);
- if (ktypes == NULL)
- free(tgsreq.ktype);
- zapfree(tgsreq.authorization_data.ciphertext.data,
- tgsreq.authorization_data.ciphertext.length);
- krb5_free_keyblock(context, local_subkey);
- return retval;
+ krb5_free_data_contents(context, &authdata_enc.ciphertext);
+ krb5_free_keyblock(context, subkey);
+ free(defenctypes);
+ return ret;
}
More information about the cvs-krb5
mailing list