17c478bd9Sstevel@tonic-gate /*
2fc59ce43SMark Phalan  * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
312b65585SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * lib/krb5/krb/send_tgs.c
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate  * All Rights Reserved.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
137c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
147c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
157c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
16*55fea89dSDan Cross  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
257c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
267c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
277c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
30*55fea89dSDan Cross  *
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * krb5_send_tgs()
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
35159d09a2SMark Phalan #include "k5-int.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate  Sends a request to the TGS and waits for a response.
397c478bd9Sstevel@tonic-gate  options is used for the options in the KRB_TGS_REQ.
407c478bd9Sstevel@tonic-gate  timestruct values are used for from, till, rtime " " "
41*55fea89dSDan Cross  enctype is used for enctype " " ", and to encrypt the authorization data,
427c478bd9Sstevel@tonic-gate  sname is used for sname " " "
437c478bd9Sstevel@tonic-gate  addrs, if non-NULL, is used for addresses " " "
447c478bd9Sstevel@tonic-gate  authorization_dat, if non-NULL, is used for authorization_dat " " "
457c478bd9Sstevel@tonic-gate  second_ticket, if required by options, is used for the 2nd ticket in the req.
467c478bd9Sstevel@tonic-gate  in_cred is used for the ticket & session key in the KRB_AP_REQ header " " "
477c478bd9Sstevel@tonic-gate  (the KDC realm is extracted from in_cred->server's realm)
48*55fea89dSDan Cross 
497c478bd9Sstevel@tonic-gate  The response is placed into *rep.
507c478bd9Sstevel@tonic-gate  rep->response.data is set to point at allocated storage which should be
517c478bd9Sstevel@tonic-gate  freed by the caller when finished.
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate  returns system errors
547c478bd9Sstevel@tonic-gate  */
55*55fea89dSDan Cross static krb5_error_code
krb5_send_tgs_basic(krb5_context context,krb5_data * in_data,krb5_creds * in_cred,krb5_data * outbuf)56505d05c7Sgtb krb5_send_tgs_basic(krb5_context context, krb5_data *in_data, krb5_creds *in_cred, krb5_data *outbuf)
57*55fea89dSDan Cross {
587c478bd9Sstevel@tonic-gate     krb5_error_code       retval;
597c478bd9Sstevel@tonic-gate     krb5_checksum         checksum;
607c478bd9Sstevel@tonic-gate     krb5_authenticator 	  authent;
617c478bd9Sstevel@tonic-gate     krb5_ap_req 	  request;
627c478bd9Sstevel@tonic-gate     krb5_data		* scratch;
637c478bd9Sstevel@tonic-gate     krb5_data           * toutbuf;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate     /* Generate checksum */
66159d09a2SMark Phalan     if ((retval = krb5_c_make_checksum(context, context->kdc_req_sumtype,
677c478bd9Sstevel@tonic-gate 				       &in_cred->keyblock,
687c478bd9Sstevel@tonic-gate 				       KRB5_KEYUSAGE_TGS_REQ_AUTH_CKSUM,
69159d09a2SMark Phalan 				       in_data, &checksum))) {
707c478bd9Sstevel@tonic-gate 	free(checksum.contents);
717c478bd9Sstevel@tonic-gate 	return(retval);
727c478bd9Sstevel@tonic-gate     }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate     /* gen authenticator */
757c478bd9Sstevel@tonic-gate     authent.subkey = 0;
767c478bd9Sstevel@tonic-gate     authent.seq_number = 0;
777c478bd9Sstevel@tonic-gate     authent.checksum = &checksum;
787c478bd9Sstevel@tonic-gate     authent.client = in_cred->client;
797c478bd9Sstevel@tonic-gate     authent.authorization_data = in_cred->authdata;
807c478bd9Sstevel@tonic-gate     if ((retval = krb5_us_timeofday(context, &authent.ctime,
817c478bd9Sstevel@tonic-gate 				    &authent.cusec))) {
827c478bd9Sstevel@tonic-gate         free(checksum.contents);
837c478bd9Sstevel@tonic-gate 	return(retval);
847c478bd9Sstevel@tonic-gate     }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate     /* encode the authenticator */
877c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_authenticator(&authent, &scratch))) {
887c478bd9Sstevel@tonic-gate         free(checksum.contents);
897c478bd9Sstevel@tonic-gate 	return(retval);
907c478bd9Sstevel@tonic-gate     }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate     free(checksum.contents);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate     request.authenticator.ciphertext.data = 0;
957c478bd9Sstevel@tonic-gate     request.authenticator.kvno = 0;
967c478bd9Sstevel@tonic-gate     request.ap_options = 0;
977c478bd9Sstevel@tonic-gate     request.ticket = 0;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate     if ((retval = decode_krb5_ticket(&(in_cred)->ticket, &request.ticket)))
1007c478bd9Sstevel@tonic-gate 	/* Cleanup scratch and scratch data */
1017c478bd9Sstevel@tonic-gate         goto cleanup_data;
1027c478bd9Sstevel@tonic-gate 
103*55fea89dSDan Cross     /* call the encryption routine */
1047c478bd9Sstevel@tonic-gate     if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
1057c478bd9Sstevel@tonic-gate 				      KRB5_KEYUSAGE_TGS_REQ_AUTH,
1067c478bd9Sstevel@tonic-gate 				      scratch, &request.authenticator)))
1077c478bd9Sstevel@tonic-gate 	goto cleanup_ticket;
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate     retval = encode_krb5_ap_req(&request, &toutbuf);
110fc59ce43SMark Phalan     /* Solaris Kerberos */
111fc59ce43SMark Phalan     if (retval == 0) {
112fc59ce43SMark Phalan 	*outbuf = *toutbuf;
113fc59ce43SMark Phalan 	krb5_xfree(toutbuf);
114fc59ce43SMark Phalan     }
1157c478bd9Sstevel@tonic-gate 
116159d09a2SMark Phalan 
1177c478bd9Sstevel@tonic-gate     memset(request.authenticator.ciphertext.data, 0,
1187c478bd9Sstevel@tonic-gate            request.authenticator.ciphertext.length);
1197c478bd9Sstevel@tonic-gate     free(request.authenticator.ciphertext.data);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate cleanup_ticket:
1227c478bd9Sstevel@tonic-gate     krb5_free_ticket(context, request.ticket);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate cleanup_data:
1257c478bd9Sstevel@tonic-gate     memset(scratch->data, 0, scratch->length);
1267c478bd9Sstevel@tonic-gate     free(scratch->data);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate     free(scratch);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate     return retval;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 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)134505d05c7Sgtb krb5_send_tgs(krb5_context context, krb5_flags kdcoptions,
135505d05c7Sgtb 	      const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
136505d05c7Sgtb 	      krb5_const_principal sname, krb5_address *const *addrs,
137505d05c7Sgtb 	      krb5_authdata *const *authorization_data,
138505d05c7Sgtb 	      krb5_pa_data *const *padata, const krb5_data *second_ticket,
139505d05c7Sgtb 	      krb5_creds *in_cred, krb5_response *rep)
1405e01956fSGlenn Barry {
1415e01956fSGlenn Barry 	return (krb5_send_tgs2(context, kdcoptions,
1425e01956fSGlenn Barry 			    timestruct, ktypes,
1435e01956fSGlenn Barry 			    sname, addrs,
1445e01956fSGlenn Barry 			    authorization_data,
1455e01956fSGlenn Barry 			    padata, second_ticket,
1465e01956fSGlenn Barry 			    in_cred, rep,
1475e01956fSGlenn Barry 			    NULL));
1485e01956fSGlenn Barry }
1495e01956fSGlenn Barry 
1505e01956fSGlenn Barry /*
1515e01956fSGlenn Barry  * Solaris Kerberos
1525e01956fSGlenn Barry  * Same as krb5_send_tgs plus an extra arg to return the FQDN
1535e01956fSGlenn Barry  * of the KDC sent the request.
1545e01956fSGlenn Barry  */
1555e01956fSGlenn Barry krb5_error_code
krb5_send_tgs2(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,char ** hostname_used)1565e01956fSGlenn Barry krb5_send_tgs2(krb5_context context, krb5_flags kdcoptions,
1575e01956fSGlenn Barry 	      const krb5_ticket_times *timestruct, const krb5_enctype *ktypes,
1585e01956fSGlenn Barry 	      krb5_const_principal sname, krb5_address *const *addrs,
1595e01956fSGlenn Barry 	      krb5_authdata *const *authorization_data,
1605e01956fSGlenn Barry 	      krb5_pa_data *const *padata, const krb5_data *second_ticket,
1615e01956fSGlenn Barry 	    krb5_creds *in_cred, krb5_response *rep, char **hostname_used)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate     krb5_error_code retval;
1647c478bd9Sstevel@tonic-gate     krb5_kdc_req tgsreq;
1657c478bd9Sstevel@tonic-gate     krb5_data *scratch, scratch2;
1667c478bd9Sstevel@tonic-gate     krb5_ticket *sec_ticket = 0;
1677c478bd9Sstevel@tonic-gate     krb5_ticket *sec_ticket_arr[2];
1687c478bd9Sstevel@tonic-gate     krb5_timestamp time_now;
1697c478bd9Sstevel@tonic-gate     krb5_pa_data **combined_padata;
1707c478bd9Sstevel@tonic-gate     krb5_pa_data ap_req_padata;
171505d05c7Sgtb     int tcp_only = 0, use_master;
1727c478bd9Sstevel@tonic-gate 
173*55fea89dSDan Cross     /*
1747c478bd9Sstevel@tonic-gate      * in_creds MUST be a valid credential NOT just a partially filled in
1757c478bd9Sstevel@tonic-gate      * place holder for us to get credentials for the caller.
1767c478bd9Sstevel@tonic-gate      */
1777c478bd9Sstevel@tonic-gate     if (!in_cred->ticket.length)
1787c478bd9Sstevel@tonic-gate         return(KRB5_NO_TKT_SUPPLIED);
1797c478bd9Sstevel@tonic-gate 
18012b65585SGordon Ross     /* Solaris Kerberos (illumos) */
18112b65585SGordon Ross     if (krb5_getenv("MS_INTEROP")) {
18212b65585SGordon Ross         /* Don't bother with UDP. */
18312b65585SGordon Ross         tcp_only = 1;
18412b65585SGordon Ross     }
18512b65585SGordon Ross 
1867c478bd9Sstevel@tonic-gate     memset((char *)&tgsreq, 0, sizeof(tgsreq));
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate     tgsreq.kdc_options = kdcoptions;
1897c478bd9Sstevel@tonic-gate     tgsreq.server = (krb5_principal) sname;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate     tgsreq.from = timestruct->starttime;
1927c478bd9Sstevel@tonic-gate     tgsreq.till = timestruct->endtime ? timestruct->endtime :
1937c478bd9Sstevel@tonic-gate 	    in_cred->times.endtime;
1947c478bd9Sstevel@tonic-gate     tgsreq.rtime = timestruct->renew_till;
1957c478bd9Sstevel@tonic-gate     if ((retval = krb5_timeofday(context, &time_now)))
1967c478bd9Sstevel@tonic-gate 	return(retval);
1977c478bd9Sstevel@tonic-gate     /* XXX we know they are the same size... */
1987c478bd9Sstevel@tonic-gate     rep->expected_nonce = tgsreq.nonce = (krb5_int32) time_now;
1997c478bd9Sstevel@tonic-gate     rep->request_time = time_now;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate     tgsreq.addresses = (krb5_address **) addrs;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate     if (authorization_data) {
2047c478bd9Sstevel@tonic-gate 	/* need to encrypt it in the request */
2057c478bd9Sstevel@tonic-gate 
206ba7b222eSGlenn Barry 	if ((retval = encode_krb5_authdata(authorization_data,
2077c478bd9Sstevel@tonic-gate 					   &scratch)))
2087c478bd9Sstevel@tonic-gate 	    return(retval);
2097c478bd9Sstevel@tonic-gate 
210159d09a2SMark Phalan 	if ((retval = krb5_encrypt_helper(context, &in_cred->keyblock,
2117c478bd9Sstevel@tonic-gate 					  KRB5_KEYUSAGE_TGS_REQ_AD_SESSKEY,
212159d09a2SMark Phalan 					  scratch,
213159d09a2SMark Phalan 					  &tgsreq.authorization_data))) {
2147c478bd9Sstevel@tonic-gate 	    krb5_xfree(tgsreq.authorization_data.ciphertext.data);
2157c478bd9Sstevel@tonic-gate 	    krb5_free_data(context, scratch);
2167c478bd9Sstevel@tonic-gate 	    return retval;
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	krb5_free_data(context, scratch);
2207c478bd9Sstevel@tonic-gate     }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate     /* Get the encryption types list */
2237c478bd9Sstevel@tonic-gate     if (ktypes) {
2247c478bd9Sstevel@tonic-gate 	/* Check passed ktypes and make sure they're valid. */
2257c478bd9Sstevel@tonic-gate    	for (tgsreq.nktypes = 0; ktypes[tgsreq.nktypes]; tgsreq.nktypes++) {
226505d05c7Sgtb     	    if (!krb5_c_valid_enctype(ktypes[tgsreq.nktypes]))
2277c478bd9Sstevel@tonic-gate 		return KRB5_PROG_ETYPE_NOSUPP;
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate     	tgsreq.ktype = (krb5_enctype *)ktypes;
2307c478bd9Sstevel@tonic-gate     } else {
2317c478bd9Sstevel@tonic-gate         /* Get the default ktypes */
232fc59ce43SMark Phalan 	/* Solaris Kerberos */
233fc59ce43SMark Phalan 	if ((retval = krb5_get_tgs_ktypes(context, sname, &(tgsreq.ktype))))
234fc59ce43SMark Phalan 		goto send_tgs_error_2;
2357c478bd9Sstevel@tonic-gate 	for(tgsreq.nktypes = 0; tgsreq.ktype[tgsreq.nktypes]; tgsreq.nktypes++);
2367c478bd9Sstevel@tonic-gate     }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate     if (second_ticket) {
2397c478bd9Sstevel@tonic-gate 	if ((retval = decode_krb5_ticket(second_ticket, &sec_ticket)))
2407c478bd9Sstevel@tonic-gate 	    goto send_tgs_error_1;
2417c478bd9Sstevel@tonic-gate 	sec_ticket_arr[0] = sec_ticket;
2427c478bd9Sstevel@tonic-gate 	sec_ticket_arr[1] = 0;
2437c478bd9Sstevel@tonic-gate 	tgsreq.second_ticket = sec_ticket_arr;
2447c478bd9Sstevel@tonic-gate     } else
2457c478bd9Sstevel@tonic-gate 	tgsreq.second_ticket = 0;
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate     /* encode the body; then checksum it */
2487c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_kdc_req_body(&tgsreq, &scratch)))
2497c478bd9Sstevel@tonic-gate 	goto send_tgs_error_2;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate     /*
2527c478bd9Sstevel@tonic-gate      * Get an ap_req.
2537c478bd9Sstevel@tonic-gate      */
2547c478bd9Sstevel@tonic-gate     if ((retval = krb5_send_tgs_basic(context, scratch, in_cred, &scratch2))) {
2557c478bd9Sstevel@tonic-gate         krb5_free_data(context, scratch);
2567c478bd9Sstevel@tonic-gate 	goto send_tgs_error_2;
2577c478bd9Sstevel@tonic-gate     }
2587c478bd9Sstevel@tonic-gate     krb5_free_data(context, scratch);
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate     ap_req_padata.pa_type = KRB5_PADATA_AP_REQ;
2617c478bd9Sstevel@tonic-gate     ap_req_padata.length = scratch2.length;
2627c478bd9Sstevel@tonic-gate     ap_req_padata.contents = (krb5_octet *)scratch2.data;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate     /* combine in any other supplied padata */
2657c478bd9Sstevel@tonic-gate     if (padata) {
2667c478bd9Sstevel@tonic-gate 	krb5_pa_data * const * counter;
2677c478bd9Sstevel@tonic-gate 	register unsigned int i = 0;
2687c478bd9Sstevel@tonic-gate 	for (counter = padata; *counter; counter++, i++);
269159d09a2SMark Phalan 	combined_padata = malloc((i+2) * sizeof(*combined_padata));
2707c478bd9Sstevel@tonic-gate 	if (!combined_padata) {
2717c478bd9Sstevel@tonic-gate 	    krb5_xfree(ap_req_padata.contents);
2727c478bd9Sstevel@tonic-gate 	    retval = ENOMEM;
2737c478bd9Sstevel@tonic-gate 	    goto send_tgs_error_2;
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 	combined_padata[0] = &ap_req_padata;
2767c478bd9Sstevel@tonic-gate 	for (i = 1, counter = padata; *counter; counter++, i++)
2777c478bd9Sstevel@tonic-gate 	    combined_padata[i] = (krb5_pa_data *) *counter;
2787c478bd9Sstevel@tonic-gate 	combined_padata[i] = 0;
2797c478bd9Sstevel@tonic-gate     } else {
2807c478bd9Sstevel@tonic-gate 	combined_padata = (krb5_pa_data **)malloc(2*sizeof(*combined_padata));
2817c478bd9Sstevel@tonic-gate 	if (!combined_padata) {
2827c478bd9Sstevel@tonic-gate 	    krb5_xfree(ap_req_padata.contents);
2837c478bd9Sstevel@tonic-gate 	    retval = ENOMEM;
2847c478bd9Sstevel@tonic-gate 	    goto send_tgs_error_2;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	combined_padata[0] = &ap_req_padata;
2877c478bd9Sstevel@tonic-gate 	combined_padata[1] = 0;
2887c478bd9Sstevel@tonic-gate     }
2897c478bd9Sstevel@tonic-gate     tgsreq.padata = combined_padata;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate     /* the TGS_REQ is assembled in tgsreq, so encode it */
2927c478bd9Sstevel@tonic-gate     if ((retval = encode_krb5_tgs_req(&tgsreq, &scratch))) {
2937c478bd9Sstevel@tonic-gate 	krb5_xfree(ap_req_padata.contents);
2947c478bd9Sstevel@tonic-gate 	krb5_xfree(combined_padata);
2957c478bd9Sstevel@tonic-gate 	goto send_tgs_error_2;
2967c478bd9Sstevel@tonic-gate     }
2977c478bd9Sstevel@tonic-gate     krb5_xfree(ap_req_padata.contents);
2987c478bd9Sstevel@tonic-gate     krb5_xfree(combined_padata);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate     /* now send request & get response from KDC */
3017c478bd9Sstevel@tonic-gate send_again:
302505d05c7Sgtb     use_master = 0;
303*55fea89dSDan Cross     retval = krb5_sendto_kdc2(context, scratch,
3045e01956fSGlenn Barry 			    krb5_princ_realm(context, sname),
3055e01956fSGlenn Barry 			    &rep->response, &use_master, tcp_only,
3065e01956fSGlenn Barry 			    hostname_used);
3077c478bd9Sstevel@tonic-gate     if (retval == 0) {
3087c478bd9Sstevel@tonic-gate 	if (krb5_is_krb_error(&rep->response)) {
3097c478bd9Sstevel@tonic-gate 	    if (!tcp_only) {
3107c478bd9Sstevel@tonic-gate 		krb5_error *err_reply;
3117c478bd9Sstevel@tonic-gate 		retval = decode_krb5_error(&rep->response, &err_reply);
312159d09a2SMark Phalan 		/* Solaris Kerberos */
3137c478bd9Sstevel@tonic-gate 		if (retval == 0) {
3147c478bd9Sstevel@tonic-gate 		    if (err_reply->error == KRB_ERR_RESPONSE_TOO_BIG) {
3157c478bd9Sstevel@tonic-gate 			tcp_only = 1;
3167c478bd9Sstevel@tonic-gate 			krb5_free_error(context, err_reply);
3177c478bd9Sstevel@tonic-gate 			free(rep->response.data);
3187c478bd9Sstevel@tonic-gate 			rep->response.data = 0;
3197c478bd9Sstevel@tonic-gate 			goto send_again;
3207c478bd9Sstevel@tonic-gate 		    }
3217c478bd9Sstevel@tonic-gate 		    krb5_free_error(context, err_reply);
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 	    }
3247c478bd9Sstevel@tonic-gate 	} else if (krb5_is_tgs_rep(&rep->response))
3257c478bd9Sstevel@tonic-gate 	    rep->message_type = KRB5_TGS_REP;
3267c478bd9Sstevel@tonic-gate         else /* XXX: assume it's an error */
3277c478bd9Sstevel@tonic-gate 	    rep->message_type = KRB5_ERROR;
3287c478bd9Sstevel@tonic-gate     }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate     krb5_free_data(context, scratch);
331*55fea89dSDan Cross 
3327c478bd9Sstevel@tonic-gate send_tgs_error_2:;
333*55fea89dSDan Cross     if (sec_ticket)
3347c478bd9Sstevel@tonic-gate 	krb5_free_ticket(context, sec_ticket);
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate send_tgs_error_1:;
3377c478bd9Sstevel@tonic-gate     if (ktypes == NULL)
3387c478bd9Sstevel@tonic-gate 	krb5_xfree(tgsreq.ktype);
3397c478bd9Sstevel@tonic-gate     if (tgsreq.authorization_data.ciphertext.data) {
3407c478bd9Sstevel@tonic-gate 	memset(tgsreq.authorization_data.ciphertext.data, 0,
341*55fea89dSDan Cross                tgsreq.authorization_data.ciphertext.length);
3427c478bd9Sstevel@tonic-gate 	krb5_xfree(tgsreq.authorization_data.ciphertext.data);
3437c478bd9Sstevel@tonic-gate     }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate     return retval;
3467c478bd9Sstevel@tonic-gate }
347