send_tgs.c revision 7934:6aeeafc994de
110154Sache/* 27768Sache * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 37768Sache * Use is subject to license terms. 4939Snate */ 5939Snate 6939Snate 7939Snate/* 8939Snate * lib/krb5/krb/send_tgs.c 9939Snate * 10939Snate * Copyright 1990,1991 by the Massachusetts Institute of Technology. 11939Snate * All Rights Reserved. 12939Snate * 13939Snate * Export of this software from the United States of America may 14939Snate * require a specific license from the United States Government. 15939Snate * It is the responsibility of any person or organization contemplating 16939Snate * export to obtain such a license before exporting. 1710154Sache * 18939Snate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 19939Snate * distribute this software and its documentation for any purpose and 20939Snate * without fee is hereby granted, provided that the above copyright 21939Snate * notice appear in all copies and that both that copyright notice and 22939Snate * this permission notice appear in supporting documentation, and that 23939Snate * the name of M.I.T. not be used in advertising or publicity pertaining 24939Snate * to distribution of the software without specific, written prior 25939Snate * permission. Furthermore if you modify this software you must label 2631306Scharnier * your software as modified software and not distribute it in such a 2731306Scharnier * fashion that it might be confused with the original M.I.T. software. 2838024Sbde * M.I.T. makes no representations about the suitability of 2931306Scharnier * this software for any purpose. It is provided "as is" without express 3031306Scharnier * or implied warranty. 31939Snate * 32939Snate * 33939Snate * krb5_send_tgs() 34939Snate */ 35939Snate 36939Snate#include "k5-int.h" 3724829Sdavidn 387768Sache/* 39939Snate Sends a request to the TGS and waits for a response. 4031306Scharnier options is used for the options in the KRB_TGS_REQ. 4131306Scharnier timestruct values are used for from, till, rtime " " " 42939Snate enctype is used for enctype " " ", and to encrypt the authorization data, 43939Snate sname is used for sname " " " 44939Snate addrs, if non-NULL, is used for addresses " " " 45939Snate authorization_dat, if non-NULL, is used for authorization_dat " " " 46939Snate second_ticket, if required by options, is used for the 2nd ticket in the req. 47939Snate in_cred is used for the ticket & session key in the KRB_AP_REQ header " " " 4831306Scharnier (the KDC realm is extracted from in_cred->server's realm) 49939Snate 50939Snate The response is placed into *rep. 5124829Sdavidn rep->response.data is set to point at allocated storage which should be 5210154Sache freed by the caller when finished. 5310154Sache 5410154Sache returns system errors 557768Sache */ 567768Sachestatic krb5_error_code 57939Snatekrb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf) 5824829Sdavidn{ 5924829Sdavidn krb5_error_code retval; 6024829Sdavidn krb5_checksum checksum; 6124829Sdavidn krb5_authenticator authent; 6224829Sdavidn krb5_ap_req request; 6324829Sdavidn krb5_data * scratch; 64939Snate krb5_data * toutbuf; 65939Snate 667768Sache /* Generate checksum */ 67939Snate if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype, 68939Snate &in_cred->keyblock, 69939Snate KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM, 707768Sache in_data, &checksum))) { 717768Sache free(checksum.contents); 727768Sache return(retval); 737768Sache } 747768Sache 757768Sache /* gen authenticator */ 767768Sache authent.subkey = 0; 777768Sache authent.seq_number = 0; 787768Sache authent.checksum = &checksum; 797768Sache authent.client = in_cred->client; 807768Sache authent.authorization_data = in_cred->authdata; 817768Sache if ((retval = krb5_us_timeofday(context, &authent.ctime, 827768Sache &authent.cusec))) { 837768Sache free(checksum.contents); 84939Snate return(retval); 85939Snate } 867768Sache 87939Snate /* encode the authenticator */ 8810154Sache if ((retval = encode_krb5_authenticator(&authent, &scratch))) { 8931306Scharnier free(checksum.contents); 9010154Sache return(retval); 91939Snate } 92939Snate 937768Sache free(checksum.contents); 94939Snate 957768Sache request.authenticator.ciphertext.data = 0; 96939Snate request.authenticator.kvno = 0; 97939Snate request.ap_options = 0; 9810154Sache request.ticket = 0; 997768Sache 1007768Sache if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket))) 1017768Sache /* Cleanup scratch and scratch data */ 1027768Sache goto cleanup_data; 1037768Sache 1047768Sache /* call the encryption routine */ 1057768Sache if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock, 1067768Sache KRB5_KEYUSAGE_TGS_REQ_AUTH, 1077768Sache scratch, &request.authenticator))) 1087768Sache goto cleanup_ticket; 1097768Sache 1107768Sache retval = encode_krb5_ap_req(&request, &toutbuf); 1117768Sache *outbuf = *toutbuf; 1127768Sache krb5_xfree(toutbuf); 113939Snate 1147768Sache 115939Snate memset(request.authenticator.ciphertext.data, 0, 1167768Sache request.authenticator.ciphertext.length); 1177768Sache free(request.authenticator.ciphertext.data); 1187768Sache 1197768Sachecleanup_ticket: 1207768Sache krb5_free_ticket(context, request.ticket); 1217768Sache 1227768Sachecleanup_data: 12324829Sdavidn memset(scratch->data, 0, scratch->length); 1247768Sache free(scratch->data); 1257768Sache 1267768Sache free(scratch); 12710154Sache 1287768Sache return retval; 1297768Sache} 1307768Sache 13110154Sachekrb5_error_code 13210154Sachekrb5_send_tgs(krb5_context context, krb5_flags kdcoptions, 133939Snate const krb5_ticket_times *timestruct, const krb5_enctype *ktypes, 134939Snate krb5_const_principal sname, krb5_address *const *addrs, 1357768Sache krb5_authdata *const *authorization_data, 136939Snate krb5_pa_data *const *padata, const krb5_data *second_ticket, 1377768Sache krb5_creds *in_cred, krb5_response *rep) 1387768Sache{ 13931306Scharnier krb5_error_code retval; 1407768Sache krb5_kdc_req tgsreq; 141939Snate krb5_data *scratch, scratch2; 1427768Sache krb5_ticket *sec_ticket = 0; 143939Snate krb5_ticket *sec_ticket_arr[2]; 1447768Sache krb5_timestamp time_now; 1457768Sache krb5_pa_data **combined_padata; 14631306Scharnier krb5_pa_data ap_req_padata; 14710154Sache int tcp_only = 0, use_master; 14810154Sache 1497768Sache /* 150939Snate * in_creds MUST be a valid credential NOT just a partially filled in 1517768Sache * place holder for us to get credentials for the caller. 1527768Sache */ 1537768Sache if (!in_cred->ticket.length) 1547768Sache return(KRB5_NO_TKT_SUPPLIED); 155939Snate 1567768Sache memset((char *)&tgsreq, 0, sizeof(tgsreq)); 1577768Sache 1587768Sache tgsreq.kdc_options = kdcoptions; 1597768Sache tgsreq.server = (krb5_principal) sname; 1607768Sache 16110154Sache tgsreq.from = timestruct->starttime; 1627768Sache tgsreq.till = timestruct->endtime ? timestruct->endtime : 1637768Sache in_cred->times.endtime; 164939Snate tgsreq.rtime = timestruct->renew_till; 1657768Sache if ((retval = krb5_timeofday(context, &time_now))) 166939Snate return(retval); 1677768Sache /* XXX we know they are the same size... */ 168939Snate rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now; 16910401Smpp rep->request_time = time_now; 17010401Smpp 17110401Smpp tgsreq.addresses = (krb5_address **) addrs; 17210401Smpp 17310401Smpp if (authorization_data) { 17410401Smpp /* need to encrypt it in the request */ 17510401Smpp 17610401Smpp if ((retval = encode_krb5_authdata((const krb5_authdata**)authorization_data, 17710401Smpp &scratch))) 1787768Sache return(retval); 17931306Scharnier 1807768Sache if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock, 1817768Sache KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY, 18231306Scharnier scratch, 1837768Sache &tgsreq.authorization_data))) { 18410154Sache krb5_xfree(tgsreq.authorization_data.ciphertext.data); 18531306Scharnier krb5_free_data(context, scratch); 18610154Sache return retval; 18710154Sache } 18831306Scharnier 18910154Sache krb5_free_data(context, scratch); 19010154Sache } 19110154Sache 19210154Sache /* Get the encryption types list */ 19310154Sache if (ktypes) { 19410154Sache /* Check passed ktypes and make sure they're valid. */ 19510154Sache for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) { 19610154Sache if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes])) 19710154Sache return KRB5_PROG_ETYPE_NOSUPP; 19810154Sache } 19910154Sache tgsreq.ktype = (krb5_enctype *)ktypes; 20010154Sache } else { 20110154Sache /* Get the default ktypes */ 20210154Sache krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype)); 20310154Sache for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++); 20410154Sache } 20510154Sache 20610154Sache if (second_ticket) { 2077768Sache if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket))) 20831306Scharnier goto send_tgs_error_1; 2097768Sache sec_ticket_arr[0] = sec_ticket; 2107768Sache sec_ticket_arr[1] = 0; 2117768Sache tgsreq.second_ticket = sec_ticket_arr; 21224829Sdavidn } else 21324829Sdavidn tgsreq.second_ticket = 0; 21424829Sdavidn 21524829Sdavidn /* encode the body; then checksum it */ 21610154Sache if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch))) 2177768Sache goto send_tgs_error_2; 21810154Sache 21910154Sache /* 22010154Sache * Get an ap_req. 2217768Sache */ 22210154Sache if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) { 22310154Sache krb5_free_data(context, scratch); 22438024Sbde goto send_tgs_error_2; 22538024Sbde } 22610154Sache krb5_free_data(context, scratch); 22710154Sache 22810154Sache ap_req_padata.pa_type = KRB5_PADATA_AP_REQ; 22938024Sbde ap_req_padata.length = scratch2.length; 23038024Sbde ap_req_padata.contents = (krb5_octet *)scratch2.data; 23110154Sache 23210154Sache /* combine in any other supplied padata */ 2337768Sache if (padata) { 2347768Sache krb5_pa_data * const * counter; 23531306Scharnier register unsigned int i = 0; 23610154Sache for (counter = padata; *counter; counter++, i++); 2377768Sache combined_padata = malloc((i+2) * sizeof(*combined_padata)); 2387768Sache if (!combined_padata) { 23910154Sache krb5_xfree(ap_req_padata.contents); 2407768Sache retval = ENOMEM; 2417768Sache goto send_tgs_error_2; 24231306Scharnier } 243939Snate combined_padata[0] = &ap_req_padata; 2447768Sache for (i = 1, counter = padata; *counter; counter++, i++) 2457768Sache combined_padata[i] = (krb5_pa_data *) *counter; 2467768Sache combined_padata[i] = 0; 2477768Sache } else { 2487768Sache combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata)); 249939Snate if (!combined_padata) { 2507768Sache krb5_xfree(ap_req_padata.contents); 2517768Sache retval = ENOMEM; 2527768Sache goto send_tgs_error_2; 25310154Sache } 2547768Sache combined_padata[0] = &ap_req_padata; 2557768Sache combined_padata[1] = 0; 25631306Scharnier } 257939Snate tgsreq.padata = combined_padata; 2587768Sache 2597768Sache /* the TGS_REQ is assembled in tgsreq, so encode it */ 2607768Sache if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) { 2617768Sache krb5_xfree(ap_req_padata.contents); 262939Snate krb5_xfree(combined_padata); 2637768Sache goto send_tgs_error_2; 2647768Sache } 2657768Sache krb5_xfree(ap_req_padata.contents); 266939Snate krb5_xfree(combined_padata); 2677768Sache 26831306Scharnier /* now send request & get response from KDC */ 269939Snatesend_again: 2707768Sache use_master = 0; 27131306Scharnier retval = krb5_sendto_kdc(context, scratch, 272939Snate krb5_princ_realm(context, sname), 2737768Sache &rep->response, &use_master, tcp_only); 27431306Scharnier if (retval == 0) { 275939Snate if (krb5_is_krb_error(&rep->response)) { 2767768Sache if (!tcp_only) { 27731306Scharnier krb5_error *err_reply; 278939Snate retval = decode_krb5_error(&rep->response, &err_reply); 2797768Sache /* Solaris Kerberos */ 2807768Sache if (retval == 0) { 2817768Sache if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) { 28231306Scharnier tcp_only = 1; 283939Snate krb5_free_error(context, err_reply); 2847768Sache free(rep->response.data); 285939Snate rep->response.data = 0; 2867768Sache goto send_again; 287939Snate } 2887768Sache krb5_free_error(context, err_reply); 28910154Sache } 2907768Sache } 29131306Scharnier } else if (krb5_is_tgs_rep(&rep->response)) 292939Snate rep->message_type = KRB5_TGS_REP; 29329231Sdima else /* XXX: assume it's an error */ 29431306Scharnier rep->message_type = KRB5_ERROR; 295939Snate } 29629231Sdima 29731306Scharnier krb5_free_data(context, scratch); 29829231Sdima 29929231Sdimasend_tgs_error_2:; 30031306Scharnier if (sec_ticket) 301939Snate krb5_free_ticket(context, sec_ticket); 30229231Sdima 30329231Sdimasend_tgs_error_1:; 30429231Sdima if (ktypes == NULL) 3057768Sache krb5_xfree(tgsreq.ktype); 30631306Scharnier if (tgsreq.authorization_data.ciphertext.data) { 307939Snate memset(tgsreq.authorization_data.ciphertext.data, 0, 3087768Sache tgsreq.authorization_data.ciphertext.length); 3097768Sache krb5_xfree(tgsreq.authorization_data.ciphertext.data); 3107768Sache } 3117768Sache 3127768Sache return retval; 3137768Sache} 3147768Sache