xref: /csrg-svn/lib/libtelnet/forward.c (revision 69784)
168591Sdab /*
268591Sdab  *    $Source: /mit/krb5/.cvsroot/src/appl/bsd/forward.c,v $
368591Sdab  *    $Id: forward.c,v 1.4 1993/10/15 16:41:29 tytso Exp $
468591Sdab  */
568591Sdab 
668591Sdab #ifndef lint
768591Sdab static char *rcsid_forward_c =
868591Sdab   "$Id: forward.c,v 1.4 1993/10/15 16:41:29 tytso Exp $";
968591Sdab #endif /* lint */
1068591Sdab #define LIBC_SCCS
1168591Sdab 
1268591Sdab /*-
1368591Sdab  * Copyright (c) 1993
1468591Sdab  *	The Regents of the University of California.  All rights reserved.
1568591Sdab  *
1668591Sdab  * %sccs.include.redist.c%
1768591Sdab  */
1868591Sdab 
1968591Sdab #ifndef lint
20*69784Sdab static char sccsid[] = "@(#)forward.c	8.2 (Berkeley) 05/30/95";
2168591Sdab #endif /* not lint */
2268591Sdab 
2368591Sdab 
2468591Sdab /* General-purpose forwarding routines. These routines may be put into */
25*69784Sdab /* libkrb5.a to allow widespread use */
2668591Sdab 
2768591Sdab #if defined(KRB5) && defined(FORWARD)
2868591Sdab #include <stdio.h>
2968591Sdab #include <pwd.h>
3068591Sdab #include <netdb.h>
3168591Sdab 
3268591Sdab #include <krb5/krb5.h>
3368591Sdab #include <krb5/asn1.h>
3468591Sdab #include <krb5/crc-32.h>
3568591Sdab #include <krb5/los-proto.h>
3668591Sdab #include <krb5/ext-proto.h>
3768591Sdab 
3868591Sdab #define KRB5_DEFAULT_LIFE 60*60*8   /* 8 hours */
3968591Sdab /* helper function: convert flags to necessary KDC options */
4068591Sdab #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
4168591Sdab 
4268591Sdab 
4368591Sdab 
4468591Sdab /* Get a TGT for use at the remote host */
4568591Sdab krb5_error_code
get_for_creds(etype,sumtype,rhost,client,enc_key,forwardable,outbuf)4668591Sdab get_for_creds(etype, sumtype, rhost, client, enc_key, forwardable, outbuf)
4768591Sdab      const krb5_enctype etype;
4868591Sdab      const krb5_cksumtype sumtype;
4968591Sdab      char *rhost;
5068591Sdab      krb5_principal client;
5168591Sdab      krb5_keyblock *enc_key;
5268591Sdab      int forwardable;      /* Should forwarded TGT also be forwardable? */
5368591Sdab      krb5_data *outbuf;
5468591Sdab {
5568591Sdab     struct hostent *hp;
5668591Sdab     krb5_address **addrs;
5768591Sdab     krb5_error_code retval;
5868591Sdab     krb5_data *scratch;
5968591Sdab     krb5_kdc_rep *dec_rep;
6068591Sdab     krb5_error *err_reply;
6168591Sdab     krb5_response tgsrep;
6268591Sdab     krb5_creds creds, tgt;
6368591Sdab     krb5_ccache cc;
6468591Sdab     krb5_flags kdcoptions;
6568591Sdab     krb5_timestamp now;
6668591Sdab     char *remote_host;
6768591Sdab     char **hrealms;
6868591Sdab     int i;
6968591Sdab 
7068591Sdab     if (!rhost || !(hp = gethostbyname(rhost)))
7168591Sdab       return KRB5_ERR_BAD_HOSTNAME;
7268591Sdab 
7368591Sdab     remote_host = (char *) malloc(strlen(hp->h_name)+1);
7468591Sdab     if (!remote_host)
7568591Sdab       return ENOMEM;
7668591Sdab     strcpy(remote_host, hp->h_name);
7768591Sdab 
7868591Sdab     if (retval = krb5_get_host_realm(remote_host, &hrealms)) {
7968591Sdab 	free(remote_host);
8068591Sdab 	return retval;
8168591Sdab     }
8268591Sdab     if (!hrealms[0]) {
8368591Sdab 	free(remote_host);
8468591Sdab 	krb5_xfree(hrealms);
8568591Sdab 	return KRB5_ERR_HOST_REALM_UNKNOWN;
8668591Sdab     }
8768591Sdab 
8868591Sdab     /* Count elements */
8968591Sdab     for(i=0; hp->h_addr_list[i]; i++);
9068591Sdab 
9168591Sdab     addrs = (krb5_address **) malloc ((i+1)*sizeof(*addrs));
9268591Sdab     if (!addrs)
9368591Sdab       return ENOMEM;
94*69784Sdab 
9568591Sdab     for(i=0; hp->h_addr_list[i]; i++) {
9668591Sdab 	addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
9768591Sdab 	if (addrs[i]) {
9868591Sdab 	    addrs[i]->addrtype = hp->h_addrtype;
9968591Sdab 	    addrs[i]->length   = hp->h_length;
10068591Sdab 	    addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
10168591Sdab 	    if (!addrs[i]->contents) {
10268591Sdab 		krb5_free_addresses(addrs);
10368591Sdab 		return ENOMEM;
10468591Sdab 	    }
10568591Sdab 	    else
106*69784Sdab 	      memmove ((char *)addrs[i]->contents, hp->h_addr_list[i],
10768591Sdab 		      addrs[i]->length);
10868591Sdab 	}
10968591Sdab 	else {
11068591Sdab 	    return ENOMEM;
11168591Sdab 	}
11268591Sdab     }
11368591Sdab     addrs[i] = 0;
11468591Sdab 
11568591Sdab     memset((char *)&creds, 0, sizeof(creds));
11668591Sdab     if (retval = krb5_copy_principal(client, &creds.client))
11768591Sdab       return retval;
118*69784Sdab 
11968591Sdab     if (retval = krb5_build_principal_ext(&creds.server,
12068591Sdab 					  strlen(hrealms[0]),
12168591Sdab 					  hrealms[0],
12268591Sdab 					  KRB5_TGS_NAME_SIZE,
12368591Sdab 					  KRB5_TGS_NAME,
12468591Sdab 					  client->realm.length,
12568591Sdab 					  client->realm.data,
12668591Sdab 					  0))
12768591Sdab       return retval;
128*69784Sdab 
12968591Sdab     creds.times.starttime = 0;
13068591Sdab     if (retval = krb5_timeofday(&now)) {
13168591Sdab 	return retval;
13268591Sdab     }
13368591Sdab     creds.times.endtime = now + KRB5_DEFAULT_LIFE;
13468591Sdab     creds.times.renew_till = 0;
135*69784Sdab 
13668591Sdab     if (retval = krb5_cc_default(&cc)) {
13768591Sdab 	return retval;
13868591Sdab     }
13968591Sdab 
14068591Sdab     /* fetch tgt directly from cache */
14168591Sdab     if (retval = krb5_cc_retrieve_cred (cc,
14268591Sdab 					KRB5_TC_MATCH_SRV_NAMEONLY,
14368591Sdab 					&creds,
14468591Sdab 					&tgt)) {
14568591Sdab 	return retval;
14668591Sdab     }
14768591Sdab 
14868591Sdab     /* tgt->client must be equal to creds.client */
14968591Sdab     if (!krb5_principal_compare(tgt.client, creds.client))
15068591Sdab 	return KRB5_PRINC_NOMATCH;
15168591Sdab 
15268591Sdab     if (!tgt.ticket.length)
15368591Sdab 	return(KRB5_NO_TKT_SUPPLIED);
15468591Sdab 
15568591Sdab     kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
15668591Sdab 
15768591Sdab     if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
15868591Sdab       kdcoptions &= ~(KDC_OPT_FORWARDABLE);
15968591Sdab 
16068591Sdab     if (retval = krb5_send_tgs(kdcoptions, &creds.times, etype, sumtype,
16168591Sdab 			       creds.server,
16268591Sdab 			       addrs,
16368591Sdab 			       creds.authdata,
16468591Sdab 			       0,		/* no padata */
16568591Sdab 			       0,		/* no second ticket */
16668591Sdab 			       &tgt, &tgsrep))
16768591Sdab 	return retval;
16868591Sdab 
16968591Sdab #undef cleanup
17068591Sdab #define cleanup() free(tgsrep.response.data)
17168591Sdab 
17268591Sdab     switch (tgsrep.message_type) {
17368591Sdab     case KRB5_TGS_REP:
17468591Sdab 	break;
17568591Sdab     case KRB5_ERROR:
17668591Sdab     default:
17768591Sdab 	if (!krb5_is_krb_error(&tgsrep.response)) {
17868591Sdab 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
17968591Sdab 	} else
18068591Sdab 	    retval = decode_krb5_error(&tgsrep.response, &err_reply);
18168591Sdab 	if (retval) {
18268591Sdab 	    cleanup();
18368591Sdab 	    return retval;		/* neither proper reply nor error! */
18468591Sdab 	}
18568591Sdab 
18668591Sdab 	retval = err_reply->error + ERROR_TABLE_BASE_krb5;
18768591Sdab 
18868591Sdab 	krb5_free_error(err_reply);
18968591Sdab 	cleanup();
19068591Sdab 	return retval;
19168591Sdab     }
19268591Sdab     retval = krb5_decode_kdc_rep(&tgsrep.response,
19368591Sdab 				 &tgt.keyblock,
19468591Sdab 				 etype, /* enctype */
19568591Sdab 				 &dec_rep);
196*69784Sdab 
19768591Sdab     cleanup();
19868591Sdab     if (retval)
19968591Sdab 	return retval;
20068591Sdab #undef cleanup
20168591Sdab #define cleanup() {\
20268591Sdab 	memset((char *)dec_rep->enc_part2->session->contents, 0,\
20368591Sdab 	      dec_rep->enc_part2->session->length);\
20468591Sdab 		  krb5_free_kdc_rep(dec_rep); }
20568591Sdab 
20668591Sdab     if (dec_rep->msg_type != KRB5_TGS_REP) {
20768591Sdab 	retval = KRB5KRB_AP_ERR_MSG_TYPE;
20868591Sdab 	cleanup();
20968591Sdab 	return retval;
21068591Sdab     }
211*69784Sdab 
21268591Sdab     /* now it's decrypted and ready for prime time */
21368591Sdab 
21468591Sdab     if (!krb5_principal_compare(dec_rep->client, tgt.client)) {
21568591Sdab 	cleanup();
21668591Sdab 	return KRB5_KDCREP_MODIFIED;
21768591Sdab     }
21868591Sdab 
219*69784Sdab     if (retval = mk_cred(dec_rep,
220*69784Sdab 			 etype,
22168591Sdab 			 enc_key,
22268591Sdab 			 0,
223*69784Sdab 			 0,
22468591Sdab 			 outbuf))
22568591Sdab       return retval;
22668591Sdab 
22768591Sdab     krb5_free_kdc_rep(dec_rep);
22868591Sdab 
22968591Sdab     return retval;
23068591Sdab #undef cleanup
23168591Sdab }
23268591Sdab 
23368591Sdab 
23468591Sdab 
23568591Sdab /* Create asn.1 encoded KRB-CRED message from the kdc reply. */
23668591Sdab krb5_error_code
mk_cred(dec_rep,etype,key,sender_addr,recv_addr,outbuf)23768591Sdab mk_cred(dec_rep, etype, key, sender_addr, recv_addr, outbuf)
23868591Sdab krb5_kdc_rep *dec_rep;
23968591Sdab krb5_enctype etype;
24068591Sdab krb5_keyblock *key;
24168591Sdab krb5_address *sender_addr;
24268591Sdab krb5_address *recv_addr;
24368591Sdab krb5_data *outbuf;
24468591Sdab {
24568591Sdab     krb5_error_code retval;
24668591Sdab     krb5_encrypt_block eblock;
24768591Sdab     krb5_cred ret_cred;
24868591Sdab     krb5_cred_enc_part cred_enc_part;
24968591Sdab     krb5_data *scratch;
25068591Sdab 
25168591Sdab     if (!valid_etype(etype))
25268591Sdab       return KRB5_PROG_ETYPE_NOSUPP;
25368591Sdab 
25468591Sdab     ret_cred.tickets = (krb5_ticket **) calloc(2, sizeof(*ret_cred.tickets));
25568591Sdab     if (!ret_cred.tickets)
25668591Sdab       return ENOMEM;
25768591Sdab     ret_cred.tickets[0] = dec_rep->ticket;
25868591Sdab     ret_cred.tickets[1] = 0;
25968591Sdab 
260*69784Sdab     ret_cred.enc_part.etype = etype;
26168591Sdab     ret_cred.enc_part.kvno = 0;
26268591Sdab 
263*69784Sdab     cred_enc_part.ticket_info = (krb5_cred_info **)
26468591Sdab       calloc(2, sizeof(*cred_enc_part.ticket_info));
26568591Sdab     if (!cred_enc_part.ticket_info) {
26668591Sdab 	krb5_free_tickets(ret_cred.tickets);
26768591Sdab 	return ENOMEM;
26868591Sdab     }
269*69784Sdab     cred_enc_part.ticket_info[0] = (krb5_cred_info *)
27068591Sdab       malloc(sizeof(*cred_enc_part.ticket_info[0]));
27168591Sdab     if (!cred_enc_part.ticket_info[0]) {
27268591Sdab 	krb5_free_tickets(ret_cred.tickets);
27368591Sdab 	krb5_free_cred_enc_part(cred_enc_part);
27468591Sdab 	return ENOMEM;
27568591Sdab     }
27668591Sdab     cred_enc_part.nonce = 0;
27768591Sdab 
27868591Sdab     if (retval = krb5_us_timeofday(&cred_enc_part.timestamp,
27968591Sdab 				   &cred_enc_part.usec))
28068591Sdab       return retval;
28168591Sdab 
28268591Sdab     cred_enc_part.s_address = (krb5_address *)sender_addr;
28368591Sdab     cred_enc_part.r_address = (krb5_address *)recv_addr;
28468591Sdab 
28568591Sdab     cred_enc_part.ticket_info[0]->session = dec_rep->enc_part2->session;
28668591Sdab     cred_enc_part.ticket_info[0]->client = dec_rep->client;
28768591Sdab     cred_enc_part.ticket_info[0]->server = dec_rep->enc_part2->server;
28868591Sdab     cred_enc_part.ticket_info[0]->flags  = dec_rep->enc_part2->flags;
28968591Sdab     cred_enc_part.ticket_info[0]->times  = dec_rep->enc_part2->times;
29068591Sdab     cred_enc_part.ticket_info[0]->caddrs = dec_rep->enc_part2->caddrs;
29168591Sdab 
29268591Sdab     cred_enc_part.ticket_info[1] = 0;
29368591Sdab 
29468591Sdab     /* start by encoding to-be-encrypted part of the message */
29568591Sdab 
29668591Sdab     if (retval = encode_krb5_enc_cred_part(&cred_enc_part, &scratch))
29768591Sdab       return retval;
29868591Sdab 
29968591Sdab #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); krb5_free_data(scratch); }
30068591Sdab 
30168591Sdab     /* put together an eblock for this encryption */
30268591Sdab 
30368591Sdab     krb5_use_cstype(&eblock, etype);
30468591Sdab     ret_cred.enc_part.ciphertext.length = krb5_encrypt_size(scratch->length,
30568591Sdab 						eblock.crypto_entry);
30668591Sdab     /* add padding area, and zero it */
30768591Sdab     if (!(scratch->data = realloc(scratch->data,
30868591Sdab 				  ret_cred.enc_part.ciphertext.length))) {
30968591Sdab 	/* may destroy scratch->data */
31068591Sdab 	krb5_xfree(scratch);
31168591Sdab 	return ENOMEM;
31268591Sdab     }
31368591Sdab     memset(scratch->data + scratch->length, 0,
31468591Sdab 	  ret_cred.enc_part.ciphertext.length - scratch->length);
31568591Sdab     if (!(ret_cred.enc_part.ciphertext.data =
31668591Sdab 	  malloc(ret_cred.enc_part.ciphertext.length))) {
317*69784Sdab 	retval = ENOMEM;
318*69784Sdab 	goto clean_scratch;
31968591Sdab     }
32068591Sdab 
32168591Sdab #define cleanup_encpart() {\
32268591Sdab 	(void) memset(ret_cred.enc_part.ciphertext.data, 0, \
32368591Sdab 	     ret_cred.enc_part.ciphertext.length); \
32468591Sdab 	free(ret_cred.enc_part.ciphertext.data); \
32568591Sdab 	ret_cred.enc_part.ciphertext.length = 0; \
32668591Sdab 	ret_cred.enc_part.ciphertext.data = 0;}
32768591Sdab 
32868591Sdab     /* do any necessary key pre-processing */
32968591Sdab     if (retval = krb5_process_key(&eblock, key)) {
330*69784Sdab 	goto clean_encpart;
33168591Sdab     }
33268591Sdab 
33368591Sdab #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
33468591Sdab 
33568591Sdab     /* call the encryption routine */
33668591Sdab     if (retval = krb5_encrypt((krb5_pointer) scratch->data,
33768591Sdab 			      (krb5_pointer)
338*69784Sdab 			      ret_cred.enc_part.ciphertext.data,
33968591Sdab 			      scratch->length, &eblock,
34068591Sdab 			      0)) {
341*69784Sdab 	goto clean_prockey;
34268591Sdab     }
343*69784Sdab 
34468591Sdab     /* private message is now assembled-- do some cleanup */
34568591Sdab     cleanup_scratch();
34668591Sdab 
34768591Sdab     if (retval = krb5_finish_key(&eblock)) {
348*69784Sdab 	cleanup_encpart();
349*69784Sdab 	return retval;
35068591Sdab     }
35168591Sdab     /* encode private message */
35268591Sdab     if (retval = encode_krb5_cred(&ret_cred, &scratch))  {
353*69784Sdab 	cleanup_encpart();
35468591Sdab 	return retval;
35568591Sdab     }
35668591Sdab 
35768591Sdab     cleanup_encpart();
35868591Sdab 
35968591Sdab     *outbuf = *scratch;
36068591Sdab     krb5_xfree(scratch);
36168591Sdab     return 0;
36268591Sdab 
36368591Sdab  clean_prockey:
36468591Sdab     cleanup_prockey();
36568591Sdab  clean_encpart:
36668591Sdab     cleanup_encpart();
36768591Sdab  clean_scratch:
36868591Sdab     cleanup_scratch();
36968591Sdab 
37068591Sdab     return retval;
37168591Sdab #undef cleanup_prockey
37268591Sdab #undef cleanup_encpart
37368591Sdab #undef cleanup_scratch
37468591Sdab }
37568591Sdab 
37668591Sdab 
37768591Sdab 
37868591Sdab /* Decode, decrypt and store the forwarded creds in the local ccache. */
37968591Sdab krb5_error_code
rd_and_store_for_creds(inbuf,ticket,lusername)38068591Sdab rd_and_store_for_creds(inbuf, ticket, lusername)
38168591Sdab      krb5_data *inbuf;
38268591Sdab      krb5_ticket *ticket;
38368591Sdab      char *lusername;
38468591Sdab {
38568591Sdab     krb5_encrypt_block eblock;
38668591Sdab     krb5_creds creds;
38768591Sdab     krb5_error_code retval;
38868591Sdab     char ccname[35];
38968591Sdab     krb5_ccache ccache = NULL;
39068591Sdab     struct passwd *pwd;
39168591Sdab 
392*69784Sdab     if (retval = rd_cred(inbuf, ticket->enc_part2->session,
39368591Sdab 			 &creds, 0, 0)) {
39468591Sdab 	return(retval);
39568591Sdab     }
396*69784Sdab 
39768591Sdab     if (!(pwd = (struct passwd *) getpwnam(lusername))) {
39868591Sdab 	return -1;
39968591Sdab     }
40068591Sdab 
40168591Sdab     sprintf(ccname, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
40268591Sdab 
40368591Sdab     if (retval = krb5_cc_resolve(ccname, &ccache)) {
40468591Sdab 	return(retval);
40568591Sdab     }
40668591Sdab 
40768591Sdab     if (retval = krb5_cc_initialize(ccache,
40868591Sdab 				    ticket->enc_part2->client)) {
40968591Sdab 	return(retval);
41068591Sdab     }
41168591Sdab 
41268591Sdab     if (retval = krb5_cc_store_cred(ccache, &creds)) {
41368591Sdab 	return(retval);
41468591Sdab     }
41568591Sdab 
41668591Sdab     if (retval = chown(ccname+5, pwd->pw_uid, -1)) {
41768591Sdab 	return(retval);
41868591Sdab     }
41968591Sdab 
42068591Sdab     return retval;
42168591Sdab }
42268591Sdab 
42368591Sdab 
42468591Sdab 
425*69784Sdab extern krb5_deltat krb5_clockskew;
42668591Sdab #define in_clock_skew(date) (abs((date)-currenttime) < krb5_clockskew)
42768591Sdab 
42868591Sdab /* Decode the KRB-CRED message, and return creds */
42968591Sdab krb5_error_code
rd_cred(inbuf,key,creds,sender_addr,recv_addr)43068591Sdab rd_cred(inbuf, key, creds, sender_addr, recv_addr)
43168591Sdab const krb5_data *inbuf;
43268591Sdab const krb5_keyblock *key;
433*69784Sdab krb5_creds *creds;		  /* Filled in */
43468591Sdab const krb5_address *sender_addr;  /* optional */
435*69784Sdab const krb5_address *recv_addr;	  /* optional */
43668591Sdab {
43768591Sdab     krb5_error_code retval;
43868591Sdab     krb5_encrypt_block eblock;
43968591Sdab     krb5_cred *credmsg;
44068591Sdab     krb5_cred_enc_part *credmsg_enc_part;
44168591Sdab     krb5_data *scratch;
44268591Sdab     krb5_timestamp currenttime;
44368591Sdab 
44468591Sdab     if (!krb5_is_krb_cred(inbuf))
44568591Sdab 	return KRB5KRB_AP_ERR_MSG_TYPE;
446*69784Sdab 
44768591Sdab     /* decode private message */
44868591Sdab     if (retval = decode_krb5_cred(inbuf, &credmsg))  {
44968591Sdab 	return retval;
45068591Sdab     }
451*69784Sdab 
45268591Sdab #define cleanup_credmsg() {(void)krb5_xfree(credmsg->enc_part.ciphertext.data); (void)krb5_xfree(credmsg);}
45368591Sdab 
45468591Sdab     if (!(scratch = (krb5_data *) malloc(sizeof(*scratch)))) {
45568591Sdab 	cleanup_credmsg();
45668591Sdab 	return ENOMEM;
45768591Sdab     }
45868591Sdab 
45968591Sdab #define cleanup_scratch() {(void)memset(scratch->data, 0, scratch->length); (void)krb5_xfree(scratch->data);}
46068591Sdab 
46168591Sdab     if (retval = encode_krb5_ticket(credmsg->tickets[0], &scratch)) {
46268591Sdab 	cleanup_credmsg();
46368591Sdab 	cleanup_scratch();
46468591Sdab 	return(retval);
46568591Sdab     }
46668591Sdab 
46768591Sdab     creds->ticket = *scratch;
46868591Sdab     if (!(creds->ticket.data = malloc(scratch->length))) {
46968591Sdab 	krb5_xfree(creds->ticket.data);
47068591Sdab 	return ENOMEM;
47168591Sdab     }
472*69784Sdab     memmove((char *)creds->ticket.data, (char *) scratch->data, scratch->length);
47368591Sdab 
47468591Sdab     cleanup_scratch();
47568591Sdab 
47668591Sdab     if (!valid_etype(credmsg->enc_part.etype)) {
47768591Sdab 	cleanup_credmsg();
47868591Sdab 	return KRB5_PROG_ETYPE_NOSUPP;
47968591Sdab     }
48068591Sdab 
48168591Sdab     /* put together an eblock for this decryption */
48268591Sdab 
48368591Sdab     krb5_use_cstype(&eblock, credmsg->enc_part.etype);
48468591Sdab     scratch->length = credmsg->enc_part.ciphertext.length;
485*69784Sdab 
48668591Sdab     if (!(scratch->data = malloc(scratch->length))) {
48768591Sdab 	cleanup_credmsg();
488*69784Sdab 	return ENOMEM;
48968591Sdab     }
49068591Sdab 
49168591Sdab     /* do any necessary key pre-processing */
49268591Sdab     if (retval = krb5_process_key(&eblock, key)) {
493*69784Sdab 	cleanup_credmsg();
49468591Sdab 	cleanup_scratch();
49568591Sdab 	return retval;
49668591Sdab     }
497*69784Sdab 
49868591Sdab #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
499*69784Sdab 
50068591Sdab     /* call the decryption routine */
50168591Sdab     if (retval = krb5_decrypt((krb5_pointer) credmsg->enc_part.ciphertext.data,
50268591Sdab 			      (krb5_pointer) scratch->data,
50368591Sdab 			      scratch->length, &eblock,
50468591Sdab 			      0)) {
50568591Sdab 	cleanup_credmsg();
50668591Sdab 	cleanup_scratch();
507*69784Sdab 	cleanup_prockey();
50868591Sdab 	return retval;
50968591Sdab     }
51068591Sdab 
51168591Sdab     /* cred message is now decrypted -- do some cleanup */
51268591Sdab 
51368591Sdab     cleanup_credmsg();
51468591Sdab 
51568591Sdab     if (retval = krb5_finish_key(&eblock)) {
516*69784Sdab 	cleanup_scratch();
517*69784Sdab 	return retval;
51868591Sdab     }
51968591Sdab 
52068591Sdab     /*  now decode the decrypted stuff */
52168591Sdab     if (retval = decode_krb5_enc_cred_part(scratch, &credmsg_enc_part)) {
52268591Sdab 	cleanup_scratch();
52368591Sdab 	return retval;
52468591Sdab     }
52568591Sdab     cleanup_scratch();
52668591Sdab 
52768591Sdab #define cleanup_mesg() {(void)krb5_xfree(credmsg_enc_part);}
52868591Sdab 
52968591Sdab     if (retval = krb5_timeofday(&currenttime)) {
53068591Sdab 	cleanup_mesg();
53168591Sdab 	return retval;
53268591Sdab     }
53368591Sdab     if (!in_clock_skew(credmsg_enc_part->timestamp)) {
534*69784Sdab 	cleanup_mesg();
53568591Sdab 	return KRB5KRB_AP_ERR_SKEW;
53668591Sdab     }
53768591Sdab 
53868591Sdab     if (sender_addr && credmsg_enc_part->s_address &&
539*69784Sdab 	!krb5_address_compare(sender_addr,
54068591Sdab 			      credmsg_enc_part->s_address)) {
54168591Sdab 	cleanup_mesg();
54268591Sdab 	return KRB5KRB_AP_ERR_BADADDR;
54368591Sdab     }
54468591Sdab     if (recv_addr && credmsg_enc_part->r_address &&
545*69784Sdab 	!krb5_address_compare(recv_addr,
54668591Sdab 			      credmsg_enc_part->r_address)) {
54768591Sdab 	cleanup_mesg();
54868591Sdab 	return KRB5KRB_AP_ERR_BADADDR;
549*69784Sdab     }
55068591Sdab 
55168591Sdab     if (credmsg_enc_part->r_address) {
55268591Sdab 	krb5_address **our_addrs;
553*69784Sdab 
55468591Sdab 	if (retval = krb5_os_localaddr(&our_addrs)) {
55568591Sdab 	    cleanup_mesg();
55668591Sdab 	    return retval;
55768591Sdab 	}
558*69784Sdab 	if (!krb5_address_search(credmsg_enc_part->r_address,
55968591Sdab 				 our_addrs)) {
56068591Sdab 	    krb5_free_addresses(our_addrs);
56168591Sdab 	    cleanup_mesg();
56268591Sdab 	    return KRB5KRB_AP_ERR_BADADDR;
56368591Sdab 	}
56468591Sdab 	krb5_free_addresses(our_addrs);
56568591Sdab     }
56668591Sdab 
56768591Sdab     if (retval = krb5_copy_principal(credmsg_enc_part->ticket_info[0]->client,
56868591Sdab 				     &creds->client)) {
56968591Sdab 	return(retval);
57068591Sdab     }
57168591Sdab 
57268591Sdab     if (retval = krb5_copy_principal(credmsg_enc_part->ticket_info[0]->server,
57368591Sdab 				     &creds->server)) {
57468591Sdab 	return(retval);
575*69784Sdab     }
57668591Sdab 
57768591Sdab     if (retval =
578*69784Sdab 	krb5_copy_keyblock_contents(credmsg_enc_part->ticket_info[0]->session,
57968591Sdab 				    &creds->keyblock)) {
58068591Sdab 	return(retval);
58168591Sdab     }
58268591Sdab 
58368591Sdab #undef clean
58468591Sdab #define clean() {\
58568591Sdab 	memset((char *)creds->keyblock.contents, 0, creds->keyblock.length);}
58668591Sdab 
58768591Sdab     creds->times = credmsg_enc_part->ticket_info[0]->times;
58868591Sdab     creds->is_skey = FALSE;
58968591Sdab     creds->ticket_flags = credmsg_enc_part->ticket_info[0]->flags;
59068591Sdab 
59168591Sdab     if (retval = krb5_copy_addresses(credmsg_enc_part->ticket_info[0]->caddrs,
59268591Sdab 				     &creds->addresses)) {
59368591Sdab 	clean();
59468591Sdab 	return(retval);
59568591Sdab     }
59668591Sdab 
59768591Sdab     creds->second_ticket.length = 0;
59868591Sdab 
59968591Sdab     creds->authdata = 0;
60068591Sdab 
60168591Sdab     cleanup_mesg();
60268591Sdab     return 0;
60368591Sdab #undef clean
60468591Sdab #undef cleanup_credmsg
60568591Sdab #undef cleanup_scratch
60668591Sdab #undef cleanup_prockey
60768591Sdab #undef cleanup_mesg
60868591Sdab }
60968591Sdab 
61068591Sdab #endif /* defined(KRB5) && defined(FORWARD) */
611