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