diff options
author | Greg Hudson <ghudson@mit.edu> | 2013-02-08 00:18:50 -0500 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2013-02-08 14:03:52 -0500 |
commit | 8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f (patch) | |
tree | 8b33622af4fbc965b52db6349239640c97d547b2 /src | |
parent | 6d78c1e7b1588500050a044c2c831994c9becaaa (diff) | |
download | krb5-8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f.tar.gz krb5-8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f.tar.xz krb5-8510f8949a7b92fa8c1b0e3b5c0764ea27eaba6f.zip |
Modernize send_tgs.c
Bring send_tgs.c up to date with current coding practices. No
functional changes.
Diffstat (limited to 'src')
-rw-r--r-- | 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 b215acfa4..89ac529cc 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; } |