xref: /csrg-svn/lib/libtelnet/forward.c (revision 68591)
1*68591Sdab /*
2*68591Sdab  *    $Source: /mit/krb5/.cvsroot/src/appl/bsd/forward.c,v $
3*68591Sdab  *    $Id: forward.c,v 1.4 1993/10/15 16:41:29 tytso Exp $
4*68591Sdab  */
5*68591Sdab 
6*68591Sdab #ifndef lint
7*68591Sdab static char *rcsid_forward_c =
8*68591Sdab   "$Id: forward.c,v 1.4 1993/10/15 16:41:29 tytso Exp $";
9*68591Sdab #endif /* lint */
10*68591Sdab #define LIBC_SCCS
11*68591Sdab 
12*68591Sdab /*-
13*68591Sdab  * Copyright (c) 1993
14*68591Sdab  *	The Regents of the University of California.  All rights reserved.
15*68591Sdab  *
16*68591Sdab  * %sccs.include.redist.c%
17*68591Sdab  */
18*68591Sdab 
19*68591Sdab #ifndef lint
20*68591Sdab static char sccsid[] = "@(#)forward.c	8.1 (Berkeley) 03/24/95";
21*68591Sdab #endif /* not lint */
22*68591Sdab 
23*68591Sdab 
24*68591Sdab /* General-purpose forwarding routines. These routines may be put into */
25*68591Sdab /* libkrb5.a to allow widespread use */
26*68591Sdab 
27*68591Sdab #if defined(KRB5) && defined(FORWARD)
28*68591Sdab #include <stdio.h>
29*68591Sdab #include <pwd.h>
30*68591Sdab #include <netdb.h>
31*68591Sdab 
32*68591Sdab #include <krb5/krb5.h>
33*68591Sdab #include <krb5/asn1.h>
34*68591Sdab #include <krb5/crc-32.h>
35*68591Sdab #include <krb5/los-proto.h>
36*68591Sdab #include <krb5/ext-proto.h>
37*68591Sdab 
38*68591Sdab #define KRB5_DEFAULT_LIFE 60*60*8   /* 8 hours */
39*68591Sdab /* helper function: convert flags to necessary KDC options */
40*68591Sdab #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
41*68591Sdab 
42*68591Sdab 
43*68591Sdab 
44*68591Sdab /* Get a TGT for use at the remote host */
45*68591Sdab krb5_error_code
46*68591Sdab get_for_creds(etype, sumtype, rhost, client, enc_key, forwardable, outbuf)
47*68591Sdab      const krb5_enctype etype;
48*68591Sdab      const krb5_cksumtype sumtype;
49*68591Sdab      char *rhost;
50*68591Sdab      krb5_principal client;
51*68591Sdab      krb5_keyblock *enc_key;
52*68591Sdab      int forwardable;      /* Should forwarded TGT also be forwardable? */
53*68591Sdab      krb5_data *outbuf;
54*68591Sdab {
55*68591Sdab     struct hostent *hp;
56*68591Sdab     krb5_address **addrs;
57*68591Sdab     krb5_error_code retval;
58*68591Sdab     krb5_data *scratch;
59*68591Sdab     krb5_kdc_rep *dec_rep;
60*68591Sdab     krb5_error *err_reply;
61*68591Sdab     krb5_response tgsrep;
62*68591Sdab     krb5_creds creds, tgt;
63*68591Sdab     krb5_ccache cc;
64*68591Sdab     krb5_flags kdcoptions;
65*68591Sdab     krb5_timestamp now;
66*68591Sdab     char *remote_host;
67*68591Sdab     char **hrealms;
68*68591Sdab     int i;
69*68591Sdab 
70*68591Sdab     if (!rhost || !(hp = gethostbyname(rhost)))
71*68591Sdab       return KRB5_ERR_BAD_HOSTNAME;
72*68591Sdab 
73*68591Sdab     remote_host = (char *) malloc(strlen(hp->h_name)+1);
74*68591Sdab     if (!remote_host)
75*68591Sdab       return ENOMEM;
76*68591Sdab     strcpy(remote_host, hp->h_name);
77*68591Sdab 
78*68591Sdab     if (retval = krb5_get_host_realm(remote_host, &hrealms)) {
79*68591Sdab 	free(remote_host);
80*68591Sdab 	return retval;
81*68591Sdab     }
82*68591Sdab     if (!hrealms[0]) {
83*68591Sdab 	free(remote_host);
84*68591Sdab 	krb5_xfree(hrealms);
85*68591Sdab 	return KRB5_ERR_HOST_REALM_UNKNOWN;
86*68591Sdab     }
87*68591Sdab 
88*68591Sdab     /* Count elements */
89*68591Sdab     for(i=0; hp->h_addr_list[i]; i++);
90*68591Sdab 
91*68591Sdab     addrs = (krb5_address **) malloc ((i+1)*sizeof(*addrs));
92*68591Sdab     if (!addrs)
93*68591Sdab       return ENOMEM;
94*68591Sdab 
95*68591Sdab     for(i=0; hp->h_addr_list[i]; i++) {
96*68591Sdab 	addrs[i] = (krb5_address *) malloc(sizeof(krb5_address));
97*68591Sdab 	if (addrs[i]) {
98*68591Sdab 	    addrs[i]->addrtype = hp->h_addrtype;
99*68591Sdab 	    addrs[i]->length   = hp->h_length;
100*68591Sdab 	    addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
101*68591Sdab 	    if (!addrs[i]->contents) {
102*68591Sdab 		krb5_free_addresses(addrs);
103*68591Sdab 		return ENOMEM;
104*68591Sdab 	    }
105*68591Sdab 	    else
106*68591Sdab 	      memcpy ((char *)addrs[i]->contents, hp->h_addr_list[i],
107*68591Sdab 		      addrs[i]->length);
108*68591Sdab 	}
109*68591Sdab 	else {
110*68591Sdab 	    return ENOMEM;
111*68591Sdab 	}
112*68591Sdab     }
113*68591Sdab     addrs[i] = 0;
114*68591Sdab 
115*68591Sdab     memset((char *)&creds, 0, sizeof(creds));
116*68591Sdab     if (retval = krb5_copy_principal(client, &creds.client))
117*68591Sdab       return retval;
118*68591Sdab 
119*68591Sdab     if (retval = krb5_build_principal_ext(&creds.server,
120*68591Sdab 					  strlen(hrealms[0]),
121*68591Sdab 					  hrealms[0],
122*68591Sdab 					  KRB5_TGS_NAME_SIZE,
123*68591Sdab 					  KRB5_TGS_NAME,
124*68591Sdab 					  client->realm.length,
125*68591Sdab 					  client->realm.data,
126*68591Sdab 					  0))
127*68591Sdab       return retval;
128*68591Sdab 
129*68591Sdab     creds.times.starttime = 0;
130*68591Sdab     if (retval = krb5_timeofday(&now)) {
131*68591Sdab 	return retval;
132*68591Sdab     }
133*68591Sdab     creds.times.endtime = now + KRB5_DEFAULT_LIFE;
134*68591Sdab     creds.times.renew_till = 0;
135*68591Sdab 
136*68591Sdab     if (retval = krb5_cc_default(&cc)) {
137*68591Sdab 	return retval;
138*68591Sdab     }
139*68591Sdab 
140*68591Sdab     /* fetch tgt directly from cache */
141*68591Sdab     if (retval = krb5_cc_retrieve_cred (cc,
142*68591Sdab 					KRB5_TC_MATCH_SRV_NAMEONLY,
143*68591Sdab 					&creds,
144*68591Sdab 					&tgt)) {
145*68591Sdab 	return retval;
146*68591Sdab     }
147*68591Sdab 
148*68591Sdab     /* tgt->client must be equal to creds.client */
149*68591Sdab     if (!krb5_principal_compare(tgt.client, creds.client))
150*68591Sdab 	return KRB5_PRINC_NOMATCH;
151*68591Sdab 
152*68591Sdab     if (!tgt.ticket.length)
153*68591Sdab 	return(KRB5_NO_TKT_SUPPLIED);
154*68591Sdab 
155*68591Sdab     kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
156*68591Sdab 
157*68591Sdab     if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
158*68591Sdab       kdcoptions &= ~(KDC_OPT_FORWARDABLE);
159*68591Sdab 
160*68591Sdab     if (retval = krb5_send_tgs(kdcoptions, &creds.times, etype, sumtype,
161*68591Sdab 			       creds.server,
162*68591Sdab 			       addrs,
163*68591Sdab 			       creds.authdata,
164*68591Sdab 			       0,		/* no padata */
165*68591Sdab 			       0,		/* no second ticket */
166*68591Sdab 			       &tgt, &tgsrep))
167*68591Sdab 	return retval;
168*68591Sdab 
169*68591Sdab #undef cleanup
170*68591Sdab #define cleanup() free(tgsrep.response.data)
171*68591Sdab 
172*68591Sdab     switch (tgsrep.message_type) {
173*68591Sdab     case KRB5_TGS_REP:
174*68591Sdab 	break;
175*68591Sdab     case KRB5_ERROR:
176*68591Sdab     default:
177*68591Sdab 	if (!krb5_is_krb_error(&tgsrep.response)) {
178*68591Sdab 	    retval = KRB5KRB_AP_ERR_MSG_TYPE;
179*68591Sdab 	} else
180*68591Sdab 	    retval = decode_krb5_error(&tgsrep.response, &err_reply);
181*68591Sdab 	if (retval) {
182*68591Sdab 	    cleanup();
183*68591Sdab 	    return retval;		/* neither proper reply nor error! */
184*68591Sdab 	}
185*68591Sdab 
186*68591Sdab 	retval = err_reply->error + ERROR_TABLE_BASE_krb5;
187*68591Sdab 
188*68591Sdab 	krb5_free_error(err_reply);
189*68591Sdab 	cleanup();
190*68591Sdab 	return retval;
191*68591Sdab     }
192*68591Sdab     retval = krb5_decode_kdc_rep(&tgsrep.response,
193*68591Sdab 				 &tgt.keyblock,
194*68591Sdab 				 etype, /* enctype */
195*68591Sdab 				 &dec_rep);
196*68591Sdab 
197*68591Sdab     cleanup();
198*68591Sdab     if (retval)
199*68591Sdab 	return retval;
200*68591Sdab #undef cleanup
201*68591Sdab #define cleanup() {\
202*68591Sdab 	memset((char *)dec_rep->enc_part2->session->contents, 0,\
203*68591Sdab 	      dec_rep->enc_part2->session->length);\
204*68591Sdab 		  krb5_free_kdc_rep(dec_rep); }
205*68591Sdab 
206*68591Sdab     if (dec_rep->msg_type != KRB5_TGS_REP) {
207*68591Sdab 	retval = KRB5KRB_AP_ERR_MSG_TYPE;
208*68591Sdab 	cleanup();
209*68591Sdab 	return retval;
210*68591Sdab     }
211*68591Sdab 
212*68591Sdab     /* now it's decrypted and ready for prime time */
213*68591Sdab 
214*68591Sdab     if (!krb5_principal_compare(dec_rep->client, tgt.client)) {
215*68591Sdab 	cleanup();
216*68591Sdab 	return KRB5_KDCREP_MODIFIED;
217*68591Sdab     }
218*68591Sdab 
219*68591Sdab     if (retval = mk_cred(dec_rep,
220*68591Sdab 			 etype,
221*68591Sdab 			 enc_key,
222*68591Sdab 			 0,
223*68591Sdab 			 0,
224*68591Sdab 			 outbuf))
225*68591Sdab       return retval;
226*68591Sdab 
227*68591Sdab     krb5_free_kdc_rep(dec_rep);
228*68591Sdab 
229*68591Sdab     return retval;
230*68591Sdab #undef cleanup
231*68591Sdab }
232*68591Sdab 
233*68591Sdab 
234*68591Sdab 
235*68591Sdab /* Create asn.1 encoded KRB-CRED message from the kdc reply. */
236*68591Sdab krb5_error_code
237*68591Sdab mk_cred(dec_rep, etype, key, sender_addr, recv_addr, outbuf)
238*68591Sdab krb5_kdc_rep *dec_rep;
239*68591Sdab krb5_enctype etype;
240*68591Sdab krb5_keyblock *key;
241*68591Sdab krb5_address *sender_addr;
242*68591Sdab krb5_address *recv_addr;
243*68591Sdab krb5_data *outbuf;
244*68591Sdab {
245*68591Sdab     krb5_error_code retval;
246*68591Sdab     krb5_encrypt_block eblock;
247*68591Sdab     krb5_cred ret_cred;
248*68591Sdab     krb5_cred_enc_part cred_enc_part;
249*68591Sdab     krb5_data *scratch;
250*68591Sdab 
251*68591Sdab     if (!valid_etype(etype))
252*68591Sdab       return KRB5_PROG_ETYPE_NOSUPP;
253*68591Sdab 
254*68591Sdab     ret_cred.tickets = (krb5_ticket **) calloc(2, sizeof(*ret_cred.tickets));
255*68591Sdab     if (!ret_cred.tickets)
256*68591Sdab       return ENOMEM;
257*68591Sdab     ret_cred.tickets[0] = dec_rep->ticket;
258*68591Sdab     ret_cred.tickets[1] = 0;
259*68591Sdab 
260*68591Sdab     ret_cred.enc_part.etype = etype;
261*68591Sdab     ret_cred.enc_part.kvno = 0;
262*68591Sdab 
263*68591Sdab     cred_enc_part.ticket_info = (krb5_cred_info **)
264*68591Sdab       calloc(2, sizeof(*cred_enc_part.ticket_info));
265*68591Sdab     if (!cred_enc_part.ticket_info) {
266*68591Sdab 	krb5_free_tickets(ret_cred.tickets);
267*68591Sdab 	return ENOMEM;
268*68591Sdab     }
269*68591Sdab     cred_enc_part.ticket_info[0] = (krb5_cred_info *)
270*68591Sdab       malloc(sizeof(*cred_enc_part.ticket_info[0]));
271*68591Sdab     if (!cred_enc_part.ticket_info[0]) {
272*68591Sdab 	krb5_free_tickets(ret_cred.tickets);
273*68591Sdab 	krb5_free_cred_enc_part(cred_enc_part);
274*68591Sdab 	return ENOMEM;
275*68591Sdab     }
276*68591Sdab     cred_enc_part.nonce = 0;
277*68591Sdab 
278*68591Sdab     if (retval = krb5_us_timeofday(&cred_enc_part.timestamp,
279*68591Sdab 				   &cred_enc_part.usec))
280*68591Sdab       return retval;
281*68591Sdab 
282*68591Sdab     cred_enc_part.s_address = (krb5_address *)sender_addr;
283*68591Sdab     cred_enc_part.r_address = (krb5_address *)recv_addr;
284*68591Sdab 
285*68591Sdab     cred_enc_part.ticket_info[0]->session = dec_rep->enc_part2->session;
286*68591Sdab     cred_enc_part.ticket_info[0]->client = dec_rep->client;
287*68591Sdab     cred_enc_part.ticket_info[0]->server = dec_rep->enc_part2->server;
288*68591Sdab     cred_enc_part.ticket_info[0]->flags  = dec_rep->enc_part2->flags;
289*68591Sdab     cred_enc_part.ticket_info[0]->times  = dec_rep->enc_part2->times;
290*68591Sdab     cred_enc_part.ticket_info[0]->caddrs = dec_rep->enc_part2->caddrs;
291*68591Sdab 
292*68591Sdab     cred_enc_part.ticket_info[1] = 0;
293*68591Sdab 
294*68591Sdab     /* start by encoding to-be-encrypted part of the message */
295*68591Sdab 
296*68591Sdab     if (retval = encode_krb5_enc_cred_part(&cred_enc_part, &scratch))
297*68591Sdab       return retval;
298*68591Sdab 
299*68591Sdab #define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); krb5_free_data(scratch); }
300*68591Sdab 
301*68591Sdab     /* put together an eblock for this encryption */
302*68591Sdab 
303*68591Sdab     krb5_use_cstype(&eblock, etype);
304*68591Sdab     ret_cred.enc_part.ciphertext.length = krb5_encrypt_size(scratch->length,
305*68591Sdab 						eblock.crypto_entry);
306*68591Sdab     /* add padding area, and zero it */
307*68591Sdab     if (!(scratch->data = realloc(scratch->data,
308*68591Sdab 				  ret_cred.enc_part.ciphertext.length))) {
309*68591Sdab 	/* may destroy scratch->data */
310*68591Sdab 	krb5_xfree(scratch);
311*68591Sdab 	return ENOMEM;
312*68591Sdab     }
313*68591Sdab     memset(scratch->data + scratch->length, 0,
314*68591Sdab 	  ret_cred.enc_part.ciphertext.length - scratch->length);
315*68591Sdab     if (!(ret_cred.enc_part.ciphertext.data =
316*68591Sdab 	  malloc(ret_cred.enc_part.ciphertext.length))) {
317*68591Sdab         retval = ENOMEM;
318*68591Sdab         goto clean_scratch;
319*68591Sdab     }
320*68591Sdab 
321*68591Sdab #define cleanup_encpart() {\
322*68591Sdab 	(void) memset(ret_cred.enc_part.ciphertext.data, 0, \
323*68591Sdab 	     ret_cred.enc_part.ciphertext.length); \
324*68591Sdab 	free(ret_cred.enc_part.ciphertext.data); \
325*68591Sdab 	ret_cred.enc_part.ciphertext.length = 0; \
326*68591Sdab 	ret_cred.enc_part.ciphertext.data = 0;}
327*68591Sdab 
328*68591Sdab     /* do any necessary key pre-processing */
329*68591Sdab     if (retval = krb5_process_key(&eblock, key)) {
330*68591Sdab         goto clean_encpart;
331*68591Sdab     }
332*68591Sdab 
333*68591Sdab #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
334*68591Sdab 
335*68591Sdab     /* call the encryption routine */
336*68591Sdab     if (retval = krb5_encrypt((krb5_pointer) scratch->data,
337*68591Sdab 			      (krb5_pointer)
338*68591Sdab 			      ret_cred.enc_part.ciphertext.data,
339*68591Sdab 			      scratch->length, &eblock,
340*68591Sdab 			      0)) {
341*68591Sdab         goto clean_prockey;
342*68591Sdab     }
343*68591Sdab 
344*68591Sdab     /* private message is now assembled-- do some cleanup */
345*68591Sdab     cleanup_scratch();
346*68591Sdab 
347*68591Sdab     if (retval = krb5_finish_key(&eblock)) {
348*68591Sdab         cleanup_encpart();
349*68591Sdab         return retval;
350*68591Sdab     }
351*68591Sdab     /* encode private message */
352*68591Sdab     if (retval = encode_krb5_cred(&ret_cred, &scratch))  {
353*68591Sdab         cleanup_encpart();
354*68591Sdab 	return retval;
355*68591Sdab     }
356*68591Sdab 
357*68591Sdab     cleanup_encpart();
358*68591Sdab 
359*68591Sdab     *outbuf = *scratch;
360*68591Sdab     krb5_xfree(scratch);
361*68591Sdab     return 0;
362*68591Sdab 
363*68591Sdab  clean_prockey:
364*68591Sdab     cleanup_prockey();
365*68591Sdab  clean_encpart:
366*68591Sdab     cleanup_encpart();
367*68591Sdab  clean_scratch:
368*68591Sdab     cleanup_scratch();
369*68591Sdab 
370*68591Sdab     return retval;
371*68591Sdab #undef cleanup_prockey
372*68591Sdab #undef cleanup_encpart
373*68591Sdab #undef cleanup_scratch
374*68591Sdab }
375*68591Sdab 
376*68591Sdab 
377*68591Sdab 
378*68591Sdab /* Decode, decrypt and store the forwarded creds in the local ccache. */
379*68591Sdab krb5_error_code
380*68591Sdab rd_and_store_for_creds(inbuf, ticket, lusername)
381*68591Sdab      krb5_data *inbuf;
382*68591Sdab      krb5_ticket *ticket;
383*68591Sdab      char *lusername;
384*68591Sdab {
385*68591Sdab     krb5_encrypt_block eblock;
386*68591Sdab     krb5_creds creds;
387*68591Sdab     krb5_error_code retval;
388*68591Sdab     char ccname[35];
389*68591Sdab     krb5_ccache ccache = NULL;
390*68591Sdab     struct passwd *pwd;
391*68591Sdab 
392*68591Sdab     if (retval = rd_cred(inbuf, ticket->enc_part2->session,
393*68591Sdab 			 &creds, 0, 0)) {
394*68591Sdab 	return(retval);
395*68591Sdab     }
396*68591Sdab 
397*68591Sdab     if (!(pwd = (struct passwd *) getpwnam(lusername))) {
398*68591Sdab 	return -1;
399*68591Sdab     }
400*68591Sdab 
401*68591Sdab     sprintf(ccname, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
402*68591Sdab 
403*68591Sdab     if (retval = krb5_cc_resolve(ccname, &ccache)) {
404*68591Sdab 	return(retval);
405*68591Sdab     }
406*68591Sdab 
407*68591Sdab     if (retval = krb5_cc_initialize(ccache,
408*68591Sdab 				    ticket->enc_part2->client)) {
409*68591Sdab 	return(retval);
410*68591Sdab     }
411*68591Sdab 
412*68591Sdab     if (retval = krb5_cc_store_cred(ccache, &creds)) {
413*68591Sdab 	return(retval);
414*68591Sdab     }
415*68591Sdab 
416*68591Sdab     if (retval = chown(ccname+5, pwd->pw_uid, -1)) {
417*68591Sdab 	return(retval);
418*68591Sdab     }
419*68591Sdab 
420*68591Sdab     return retval;
421*68591Sdab }
422*68591Sdab 
423*68591Sdab 
424*68591Sdab 
425*68591Sdab extern krb5_deltat krb5_clockskew;
426*68591Sdab #define in_clock_skew(date) (abs((date)-currenttime) < krb5_clockskew)
427*68591Sdab 
428*68591Sdab /* Decode the KRB-CRED message, and return creds */
429*68591Sdab krb5_error_code
430*68591Sdab rd_cred(inbuf, key, creds, sender_addr, recv_addr)
431*68591Sdab const krb5_data *inbuf;
432*68591Sdab const krb5_keyblock *key;
433*68591Sdab krb5_creds *creds;                /* Filled in */
434*68591Sdab const krb5_address *sender_addr;  /* optional */
435*68591Sdab const krb5_address *recv_addr;    /* optional */
436*68591Sdab {
437*68591Sdab     krb5_error_code retval;
438*68591Sdab     krb5_encrypt_block eblock;
439*68591Sdab     krb5_cred *credmsg;
440*68591Sdab     krb5_cred_enc_part *credmsg_enc_part;
441*68591Sdab     krb5_data *scratch;
442*68591Sdab     krb5_timestamp currenttime;
443*68591Sdab 
444*68591Sdab     if (!krb5_is_krb_cred(inbuf))
445*68591Sdab 	return KRB5KRB_AP_ERR_MSG_TYPE;
446*68591Sdab 
447*68591Sdab     /* decode private message */
448*68591Sdab     if (retval = decode_krb5_cred(inbuf, &credmsg))  {
449*68591Sdab 	return retval;
450*68591Sdab     }
451*68591Sdab 
452*68591Sdab #define cleanup_credmsg() {(void)krb5_xfree(credmsg->enc_part.ciphertext.data); (void)krb5_xfree(credmsg);}
453*68591Sdab 
454*68591Sdab     if (!(scratch = (krb5_data *) malloc(sizeof(*scratch)))) {
455*68591Sdab 	cleanup_credmsg();
456*68591Sdab 	return ENOMEM;
457*68591Sdab     }
458*68591Sdab 
459*68591Sdab #define cleanup_scratch() {(void)memset(scratch->data, 0, scratch->length); (void)krb5_xfree(scratch->data);}
460*68591Sdab 
461*68591Sdab     if (retval = encode_krb5_ticket(credmsg->tickets[0], &scratch)) {
462*68591Sdab 	cleanup_credmsg();
463*68591Sdab 	cleanup_scratch();
464*68591Sdab 	return(retval);
465*68591Sdab     }
466*68591Sdab 
467*68591Sdab     creds->ticket = *scratch;
468*68591Sdab     if (!(creds->ticket.data = malloc(scratch->length))) {
469*68591Sdab 	krb5_xfree(creds->ticket.data);
470*68591Sdab 	return ENOMEM;
471*68591Sdab     }
472*68591Sdab     memcpy((char *)creds->ticket.data, (char *) scratch->data, scratch->length);
473*68591Sdab 
474*68591Sdab     cleanup_scratch();
475*68591Sdab 
476*68591Sdab     if (!valid_etype(credmsg->enc_part.etype)) {
477*68591Sdab 	cleanup_credmsg();
478*68591Sdab 	return KRB5_PROG_ETYPE_NOSUPP;
479*68591Sdab     }
480*68591Sdab 
481*68591Sdab     /* put together an eblock for this decryption */
482*68591Sdab 
483*68591Sdab     krb5_use_cstype(&eblock, credmsg->enc_part.etype);
484*68591Sdab     scratch->length = credmsg->enc_part.ciphertext.length;
485*68591Sdab 
486*68591Sdab     if (!(scratch->data = malloc(scratch->length))) {
487*68591Sdab 	cleanup_credmsg();
488*68591Sdab         return ENOMEM;
489*68591Sdab     }
490*68591Sdab 
491*68591Sdab     /* do any necessary key pre-processing */
492*68591Sdab     if (retval = krb5_process_key(&eblock, key)) {
493*68591Sdab         cleanup_credmsg();
494*68591Sdab 	cleanup_scratch();
495*68591Sdab 	return retval;
496*68591Sdab     }
497*68591Sdab 
498*68591Sdab #define cleanup_prockey() {(void) krb5_finish_key(&eblock);}
499*68591Sdab 
500*68591Sdab     /* call the decryption routine */
501*68591Sdab     if (retval = krb5_decrypt((krb5_pointer) credmsg->enc_part.ciphertext.data,
502*68591Sdab 			      (krb5_pointer) scratch->data,
503*68591Sdab 			      scratch->length, &eblock,
504*68591Sdab 			      0)) {
505*68591Sdab 	cleanup_credmsg();
506*68591Sdab 	cleanup_scratch();
507*68591Sdab         cleanup_prockey();
508*68591Sdab 	return retval;
509*68591Sdab     }
510*68591Sdab 
511*68591Sdab     /* cred message is now decrypted -- do some cleanup */
512*68591Sdab 
513*68591Sdab     cleanup_credmsg();
514*68591Sdab 
515*68591Sdab     if (retval = krb5_finish_key(&eblock)) {
516*68591Sdab         cleanup_scratch();
517*68591Sdab         return retval;
518*68591Sdab     }
519*68591Sdab 
520*68591Sdab     /*  now decode the decrypted stuff */
521*68591Sdab     if (retval = decode_krb5_enc_cred_part(scratch, &credmsg_enc_part)) {
522*68591Sdab 	cleanup_scratch();
523*68591Sdab 	return retval;
524*68591Sdab     }
525*68591Sdab     cleanup_scratch();
526*68591Sdab 
527*68591Sdab #define cleanup_mesg() {(void)krb5_xfree(credmsg_enc_part);}
528*68591Sdab 
529*68591Sdab     if (retval = krb5_timeofday(&currenttime)) {
530*68591Sdab 	cleanup_mesg();
531*68591Sdab 	return retval;
532*68591Sdab     }
533*68591Sdab     if (!in_clock_skew(credmsg_enc_part->timestamp)) {
534*68591Sdab 	cleanup_mesg();
535*68591Sdab 	return KRB5KRB_AP_ERR_SKEW;
536*68591Sdab     }
537*68591Sdab 
538*68591Sdab     if (sender_addr && credmsg_enc_part->s_address &&
539*68591Sdab 	!krb5_address_compare(sender_addr,
540*68591Sdab 			      credmsg_enc_part->s_address)) {
541*68591Sdab 	cleanup_mesg();
542*68591Sdab 	return KRB5KRB_AP_ERR_BADADDR;
543*68591Sdab     }
544*68591Sdab     if (recv_addr && credmsg_enc_part->r_address &&
545*68591Sdab 	!krb5_address_compare(recv_addr,
546*68591Sdab 			      credmsg_enc_part->r_address)) {
547*68591Sdab 	cleanup_mesg();
548*68591Sdab 	return KRB5KRB_AP_ERR_BADADDR;
549*68591Sdab     }
550*68591Sdab 
551*68591Sdab     if (credmsg_enc_part->r_address) {
552*68591Sdab 	krb5_address **our_addrs;
553*68591Sdab 
554*68591Sdab 	if (retval = krb5_os_localaddr(&our_addrs)) {
555*68591Sdab 	    cleanup_mesg();
556*68591Sdab 	    return retval;
557*68591Sdab 	}
558*68591Sdab 	if (!krb5_address_search(credmsg_enc_part->r_address,
559*68591Sdab 				 our_addrs)) {
560*68591Sdab 	    krb5_free_addresses(our_addrs);
561*68591Sdab 	    cleanup_mesg();
562*68591Sdab 	    return KRB5KRB_AP_ERR_BADADDR;
563*68591Sdab 	}
564*68591Sdab 	krb5_free_addresses(our_addrs);
565*68591Sdab     }
566*68591Sdab 
567*68591Sdab     if (retval = krb5_copy_principal(credmsg_enc_part->ticket_info[0]->client,
568*68591Sdab 				     &creds->client)) {
569*68591Sdab 	return(retval);
570*68591Sdab     }
571*68591Sdab 
572*68591Sdab     if (retval = krb5_copy_principal(credmsg_enc_part->ticket_info[0]->server,
573*68591Sdab 				     &creds->server)) {
574*68591Sdab 	return(retval);
575*68591Sdab     }
576*68591Sdab 
577*68591Sdab     if (retval =
578*68591Sdab 	krb5_copy_keyblock_contents(credmsg_enc_part->ticket_info[0]->session,
579*68591Sdab 				    &creds->keyblock)) {
580*68591Sdab 	return(retval);
581*68591Sdab     }
582*68591Sdab 
583*68591Sdab #undef clean
584*68591Sdab #define clean() {\
585*68591Sdab 	memset((char *)creds->keyblock.contents, 0, creds->keyblock.length);}
586*68591Sdab 
587*68591Sdab     creds->times = credmsg_enc_part->ticket_info[0]->times;
588*68591Sdab     creds->is_skey = FALSE;
589*68591Sdab     creds->ticket_flags = credmsg_enc_part->ticket_info[0]->flags;
590*68591Sdab 
591*68591Sdab     if (retval = krb5_copy_addresses(credmsg_enc_part->ticket_info[0]->caddrs,
592*68591Sdab 				     &creds->addresses)) {
593*68591Sdab 	clean();
594*68591Sdab 	return(retval);
595*68591Sdab     }
596*68591Sdab 
597*68591Sdab     creds->second_ticket.length = 0;
598*68591Sdab 
599*68591Sdab     creds->authdata = 0;
600*68591Sdab 
601*68591Sdab     cleanup_mesg();
602*68591Sdab     return 0;
603*68591Sdab #undef clean
604*68591Sdab #undef cleanup_credmsg
605*68591Sdab #undef cleanup_scratch
606*68591Sdab #undef cleanup_prockey
607*68591Sdab #undef cleanup_mesg
608*68591Sdab }
609*68591Sdab 
610*68591Sdab #endif /* defined(KRB5) && defined(FORWARD) */
611