xref: /freebsd/crypto/heimdal/lib/krb5/get_in_tkt.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "krb5_locl.h"
35 
36 RCSID("$Id: get_in_tkt.c,v 1.94 2000/02/06 05:18:20 assar Exp $");
37 
38 krb5_error_code
39 krb5_init_etype (krb5_context context,
40 		 unsigned *len,
41 		 int **val,
42 		 const krb5_enctype *etypes)
43 {
44     int i;
45     krb5_error_code ret;
46     krb5_enctype *tmp;
47 
48     ret = 0;
49     if (etypes)
50 	tmp = (krb5_enctype*)etypes;
51     else {
52 	ret = krb5_get_default_in_tkt_etypes(context,
53 					     &tmp);
54 	if (ret)
55 	    return ret;
56     }
57 
58     for (i = 0; tmp[i]; ++i)
59 	;
60     *len = i;
61     *val = malloc(i * sizeof(int));
62     if (i != 0 && *val == NULL) {
63 	ret = ENOMEM;
64 	goto cleanup;
65     }
66     memmove (*val,
67 	     tmp,
68 	     i * sizeof(*tmp));
69 cleanup:
70     if (etypes == NULL)
71 	free (tmp);
72     return ret;
73 }
74 
75 
76 static krb5_error_code
77 decrypt_tkt (krb5_context context,
78 	     krb5_keyblock *key,
79 	     krb5_key_usage usage,
80 	     krb5_const_pointer decrypt_arg,
81 	     krb5_kdc_rep *dec_rep)
82 {
83     krb5_error_code ret;
84     krb5_data data;
85     size_t size;
86     krb5_crypto crypto;
87 
88     krb5_crypto_init(context, key, 0, &crypto);
89 
90     ret = krb5_decrypt_EncryptedData (context,
91 				      crypto,
92 				      usage,
93 				      &dec_rep->kdc_rep.enc_part,
94 				      &data);
95     krb5_crypto_destroy(context, crypto);
96 
97     if (ret)
98 	return ret;
99 
100     ret = krb5_decode_EncASRepPart(context,
101 				   data.data,
102 				   data.length,
103 				   &dec_rep->enc_part,
104 				   &size);
105     if (ret)
106 	ret = krb5_decode_EncTGSRepPart(context,
107 					data.data,
108 					data.length,
109 					&dec_rep->enc_part,
110 					&size);
111     krb5_data_free (&data);
112     if (ret)
113 	return ret;
114     return 0;
115 }
116 
117 int
118 _krb5_extract_ticket(krb5_context context,
119 		     krb5_kdc_rep *rep,
120 		     krb5_creds *creds,
121 		     krb5_keyblock *key,
122 		     krb5_const_pointer keyseed,
123 		     krb5_key_usage key_usage,
124 		     krb5_addresses *addrs,
125 		     unsigned nonce,
126 		     krb5_boolean allow_server_mismatch,
127 		     krb5_decrypt_proc decrypt_proc,
128 		     krb5_const_pointer decryptarg)
129 {
130     krb5_error_code ret;
131     krb5_principal tmp_principal;
132     int tmp;
133     time_t tmp_time;
134     krb5_timestamp sec_now;
135 
136     /* compare client */
137 
138     ret = principalname2krb5_principal (&tmp_principal,
139 					rep->kdc_rep.cname,
140 					rep->kdc_rep.crealm);
141     if (ret)
142 	goto out;
143     tmp = krb5_principal_compare (context, tmp_principal, creds->client);
144     krb5_free_principal (context, tmp_principal);
145     if (!tmp) {
146 	ret = KRB5KRB_AP_ERR_MODIFIED;
147 	goto out;
148     }
149 
150     /* extract ticket */
151     {
152 	unsigned char *buf;
153 	size_t len;
154 	len = length_Ticket(&rep->kdc_rep.ticket);
155 	buf = malloc(len);
156 	if(buf == NULL) {
157 	    ret = ENOMEM;
158 	    goto out;
159 	}
160 	encode_Ticket(buf + len - 1, len, &rep->kdc_rep.ticket, &len);
161 	creds->ticket.data = buf;
162 	creds->ticket.length = len;
163 	creds->second_ticket.length = 0;
164 	creds->second_ticket.data   = NULL;
165     }
166 
167     /* compare server */
168 
169     ret = principalname2krb5_principal (&tmp_principal,
170 					rep->kdc_rep.ticket.sname,
171 					rep->kdc_rep.ticket.realm);
172     if (ret)
173 	goto out;
174     if(allow_server_mismatch){
175 	krb5_free_principal(context, creds->server);
176 	creds->server = tmp_principal;
177 	tmp_principal = NULL;
178     }else{
179 	tmp = krb5_principal_compare (context, tmp_principal, creds->server);
180 	krb5_free_principal (context, tmp_principal);
181 	if (!tmp) {
182 	    ret = KRB5KRB_AP_ERR_MODIFIED;
183 	    goto out;
184 	}
185     }
186 
187     /* decrypt */
188 
189     if (decrypt_proc == NULL)
190 	decrypt_proc = decrypt_tkt;
191 
192     ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
193     if (ret)
194 	goto out;
195 
196 #if 0
197     /* XXX should this decode be here, or in the decrypt_proc? */
198     ret = krb5_decode_keyblock(context, &rep->enc_part.key, 1);
199     if(ret)
200 	goto out;
201 #endif
202 
203     /* compare nonces */
204 
205     if (nonce != rep->enc_part.nonce) {
206 	ret = KRB5KRB_AP_ERR_MODIFIED;
207 	goto out;
208     }
209 
210     /* set kdc-offset */
211 
212     krb5_timeofday (context, &sec_now);
213     if (context->kdc_sec_offset == 0
214 	&& krb5_config_get_bool (context, NULL,
215 				 "libdefaults",
216 				 "kdc_timesync",
217 				 NULL)) {
218 	context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
219 	krb5_timeofday (context, &sec_now);
220     }
221 
222     /* check all times */
223 
224     if (rep->enc_part.starttime) {
225 	tmp_time = *rep->enc_part.starttime;
226     } else
227 	tmp_time = rep->enc_part.authtime;
228 
229     if (creds->times.starttime == 0
230 	&& abs(tmp_time - sec_now) > context->max_skew) {
231 	ret = KRB5KRB_AP_ERR_SKEW;
232 	goto out;
233     }
234 
235     if (creds->times.starttime != 0
236 	&& tmp_time != creds->times.starttime) {
237 	ret = KRB5KRB_AP_ERR_MODIFIED;
238 	goto out;
239     }
240 
241     creds->times.starttime = tmp_time;
242 
243     if (rep->enc_part.renew_till) {
244 	tmp_time = *rep->enc_part.renew_till;
245     } else
246 	tmp_time = 0;
247 
248     if (creds->times.renew_till != 0
249 	&& tmp_time > creds->times.renew_till) {
250 	ret = KRB5KRB_AP_ERR_MODIFIED;
251 	goto out;
252     }
253 
254     creds->times.renew_till = tmp_time;
255 
256     creds->times.authtime = rep->enc_part.authtime;
257 
258     if (creds->times.endtime != 0
259 	&& rep->enc_part.endtime > creds->times.endtime) {
260 	ret = KRB5KRB_AP_ERR_MODIFIED;
261 	goto out;
262     }
263 
264     creds->times.endtime  = rep->enc_part.endtime;
265 
266     if(rep->enc_part.caddr)
267 	krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
268     else if(addrs)
269 	krb5_copy_addresses (context, addrs, &creds->addresses);
270     else {
271 	creds->addresses.len = 0;
272 	creds->addresses.val = NULL;
273     }
274     creds->flags.b = rep->enc_part.flags;
275 
276     creds->authdata.len = 0;
277     creds->authdata.val = NULL;
278     creds->session.keyvalue.length = 0;
279     creds->session.keyvalue.data   = NULL;
280     creds->session.keytype = rep->enc_part.key.keytype;
281     ret = krb5_data_copy (&creds->session.keyvalue,
282 			  rep->enc_part.key.keyvalue.data,
283 			  rep->enc_part.key.keyvalue.length);
284 
285 out:
286     memset (rep->enc_part.key.keyvalue.data, 0,
287 	    rep->enc_part.key.keyvalue.length);
288     return ret;
289 }
290 
291 
292 static krb5_error_code
293 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
294 		      krb5_enctype etype, krb5_keyblock *key)
295 {
296     PA_ENC_TS_ENC p;
297     u_char buf[1024];
298     size_t len;
299     EncryptedData encdata;
300     krb5_error_code ret;
301     int32_t sec, usec;
302     int usec2;
303     krb5_crypto crypto;
304 
305     krb5_us_timeofday (context, &sec, &usec);
306     p.patimestamp = sec;
307     usec2         = usec;
308     p.pausec      = &usec2;
309 
310     ret = encode_PA_ENC_TS_ENC(buf + sizeof(buf) - 1,
311 			       sizeof(buf),
312 			       &p,
313 			       &len);
314     if (ret)
315 	return ret;
316 
317     krb5_crypto_init(context, key, 0, &crypto);
318     ret = krb5_encrypt_EncryptedData(context,
319 				     crypto,
320 				     KRB5_KU_PA_ENC_TIMESTAMP,
321 				     buf + sizeof(buf) - len,
322 				     len,
323 				     0,
324 				     &encdata);
325     krb5_crypto_destroy(context, crypto);
326     if (ret)
327 	return ret;
328 
329     ret = encode_EncryptedData(buf + sizeof(buf) - 1,
330 			       sizeof(buf),
331 			       &encdata,
332 			       &len);
333     free_EncryptedData(&encdata);
334     if (ret)
335 	return ret;
336     pa->padata_type = pa_enc_timestamp;
337     pa->padata_value.length = 0;
338     krb5_data_copy(&pa->padata_value,
339 		   buf + sizeof(buf) - len,
340 		   len);
341     return 0;
342 }
343 
344 static krb5_error_code
345 add_padata(krb5_context context,
346 	   METHOD_DATA *md,
347 	   krb5_principal client,
348 	   krb5_key_proc key_proc,
349 	   krb5_const_pointer keyseed,
350 	   int *enctypes,
351 	   unsigned netypes,
352 	   krb5_salt *salt)
353 {
354     krb5_error_code ret;
355     PA_DATA *pa2;
356     krb5_salt salt2;
357     int *ep;
358     int i;
359 
360     if(salt == NULL) {
361 	/* default to standard salt */
362 	ret = krb5_get_pw_salt (context, client, &salt2);
363 	salt = &salt2;
364     }
365     if (!enctypes) {
366 	enctypes = (int *)context->etypes; /* XXX */
367 	netypes = 0;
368 	for (ep = enctypes; *ep != ETYPE_NULL; ep++)
369 	    netypes++;
370     }
371     pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
372     if (pa2 == NULL)
373 	return ENOMEM;
374     md->val = pa2;
375 
376     for (i = 0; i < netypes; ++i) {
377 	krb5_keyblock *key;
378 
379 	ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
380 	if (ret)
381 	    continue;
382 	ret = make_pa_enc_timestamp (context, &md->val[md->len],
383 				     enctypes[i], key);
384 	krb5_free_keyblock (context, key);
385 	if (ret)
386 	    return ret;
387 	++md->len;
388     }
389     if(salt == &salt2)
390 	krb5_free_salt(context, salt2);
391     return 0;
392 }
393 
394 static krb5_error_code
395 init_as_req (krb5_context context,
396 	     krb5_kdc_flags opts,
397 	     krb5_creds *creds,
398 	     const krb5_addresses *addrs,
399 	     const krb5_enctype *etypes,
400 	     const krb5_preauthtype *ptypes,
401 	     const krb5_preauthdata *preauth,
402 	     krb5_key_proc key_proc,
403 	     krb5_const_pointer keyseed,
404 	     unsigned nonce,
405 	     AS_REQ *a)
406 {
407     krb5_error_code ret;
408     krb5_salt salt;
409 
410     memset(a, 0, sizeof(*a));
411 
412     a->pvno = 5;
413     a->msg_type = krb_as_req;
414     a->req_body.kdc_options = opts.b;
415     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
416     if (a->req_body.cname == NULL) {
417 	ret = ENOMEM;
418 	goto fail;
419     }
420     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
421     if (a->req_body.sname == NULL) {
422 	ret = ENOMEM;
423 	goto fail;
424     }
425     ret = krb5_principal2principalname (a->req_body.cname, creds->client);
426     if (ret)
427 	goto fail;
428     ret = krb5_principal2principalname (a->req_body.sname, creds->server);
429     if (ret)
430 	goto fail;
431     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
432     if (ret)
433 	goto fail;
434 
435     if(creds->times.starttime) {
436 	a->req_body.from = malloc(sizeof(*a->req_body.from));
437 	if (a->req_body.from == NULL) {
438 	    ret = ENOMEM;
439 	    goto fail;
440 	}
441 	*a->req_body.from = creds->times.starttime;
442     }
443     if(creds->times.endtime){
444 	ALLOC(a->req_body.till, 1);
445 	*a->req_body.till = creds->times.endtime;
446     }
447     if(creds->times.renew_till){
448 	a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
449 	if (a->req_body.rtime == NULL) {
450 	    ret = ENOMEM;
451 	    goto fail;
452 	}
453 	*a->req_body.rtime = creds->times.renew_till;
454     }
455     a->req_body.nonce = nonce;
456     ret = krb5_init_etype (context,
457 			   &a->req_body.etype.len,
458 			   &a->req_body.etype.val,
459 			   etypes);
460     if (ret)
461 	goto fail;
462 
463     /*
464      * This means no addresses
465      */
466 
467     if (addrs && addrs->len == 0) {
468 	a->req_body.addresses = NULL;
469     } else {
470 	a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
471 	if (a->req_body.addresses == NULL) {
472 	    ret = ENOMEM;
473 	    goto fail;
474 	}
475 
476 	if (addrs)
477 	    ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
478 	else
479 	    ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
480 	if (ret)
481 	    return ret;
482     }
483 
484     a->req_body.enc_authorization_data = NULL;
485     a->req_body.additional_tickets = NULL;
486 
487     if(preauth != NULL) {
488 	int i;
489 	ALLOC(a->padata, 1);
490 	if(a->padata == NULL) {
491 	    ret = ENOMEM;
492 	    goto fail;
493 	}
494 	for(i = 0; i < preauth->len; i++) {
495 	    if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
496 		int j;
497 		PA_DATA *tmp = realloc(a->padata->val,
498 				       (a->padata->len +
499 					preauth->val[i].info.len) *
500 				       sizeof(*a->padata->val));
501 		if(tmp == NULL) {
502 		    ret = ENOMEM;
503 		    goto fail;
504 		}
505 		a->padata->val = tmp;
506 		for(j = 0; j < preauth->val[i].info.len; j++) {
507 		    krb5_salt *sp = &salt;
508 		    if(preauth->val[i].info.val[j].salttype)
509 			salt.salttype = *preauth->val[i].info.val[j].salttype;
510 		    else
511 			salt.salttype = KRB5_PW_SALT;
512 		    if(preauth->val[i].info.val[j].salt)
513 			salt.saltvalue = *preauth->val[i].info.val[j].salt;
514 		    else
515 			if(salt.salttype == KRB5_PW_SALT)
516 			    sp = NULL;
517 			else
518 			    krb5_data_zero(&salt.saltvalue);
519 		    add_padata(context, a->padata, creds->client,
520 			       key_proc, keyseed,
521 			       &preauth->val[i].info.val[j].etype, 1,
522 			       sp);
523 		}
524 	    }
525 	}
526     } else
527     /* not sure this is the way to use `ptypes' */
528     if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
529 	a->padata = NULL;
530     else if (*ptypes ==  KRB5_PADATA_ENC_TIMESTAMP) {
531 	ALLOC(a->padata, 1);
532 	if (a->padata == NULL) {
533 	    ret = ENOMEM;
534 	    goto fail;
535 	}
536 	a->padata->len = 0;
537 	a->padata->val = NULL;
538 
539 	/* make a v5 salted pa-data */
540 	add_padata(context, a->padata, creds->client,
541 		   key_proc, keyseed, a->req_body.etype.val,
542 		   a->req_body.etype.len, NULL);
543 
544 	/* make a v4 salted pa-data */
545 	salt.salttype = KRB5_PW_SALT;
546 	krb5_data_zero(&salt.saltvalue);
547 	add_padata(context, a->padata, creds->client,
548 		   key_proc, keyseed, a->req_body.etype.val,
549 		   a->req_body.etype.len, &salt);
550     } else {
551 	ret = KRB5_PREAUTH_BAD_TYPE;
552 	goto fail;
553     }
554     return 0;
555 fail:
556     free_AS_REQ(a);
557     return ret;
558 }
559 
560 static int
561 set_ptypes(krb5_context context,
562 	   KRB_ERROR *error,
563 	   krb5_preauthtype **ptypes,
564 	   krb5_preauthdata **preauth)
565 {
566     static krb5_preauthdata preauth2;
567     static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
568 
569     if(error->e_data) {
570 	METHOD_DATA md;
571 	int i;
572 	decode_METHOD_DATA(error->e_data->data,
573 			   error->e_data->length,
574 			   &md,
575 			   NULL);
576 	for(i = 0; i < md.len; i++){
577 	    switch(md.val[i].padata_type){
578 	    case pa_enc_timestamp:
579 		*ptypes = ptypes2;
580 		break;
581 	    case pa_etype_info:
582 		*preauth = &preauth2;
583 		ALLOC_SEQ(*preauth, 1);
584 		(*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
585 		krb5_decode_ETYPE_INFO(context,
586 				       md.val[i].padata_value.data,
587 				       md.val[i].padata_value.length,
588 				       &(*preauth)->val[0].info,
589 				       NULL);
590 		break;
591 	    }
592 	}
593 	free_METHOD_DATA(&md);
594     } else {
595 	*ptypes = ptypes2;
596     }
597     return(1);
598 }
599 
600 krb5_error_code
601 krb5_get_in_cred(krb5_context context,
602 		 krb5_flags options,
603 		 const krb5_addresses *addrs,
604 		 const krb5_enctype *etypes,
605 		 const krb5_preauthtype *ptypes,
606 		 const krb5_preauthdata *preauth,
607 		 krb5_key_proc key_proc,
608 		 krb5_const_pointer keyseed,
609 		 krb5_decrypt_proc decrypt_proc,
610 		 krb5_const_pointer decryptarg,
611 		 krb5_creds *creds,
612 		 krb5_kdc_rep *ret_as_reply)
613 {
614     krb5_error_code ret;
615     AS_REQ a;
616     krb5_kdc_rep rep;
617     krb5_data req, resp;
618     char buf[BUFSIZ];
619     krb5_salt salt;
620     krb5_keyblock *key;
621     size_t size;
622     krb5_kdc_flags opts;
623     PA_DATA *pa;
624     krb5_enctype etype;
625     krb5_preauthdata *my_preauth = NULL;
626     unsigned nonce;
627     int done;
628 
629     opts.i = options;
630 
631     krb5_generate_random_block (&nonce, sizeof(nonce));
632     nonce &= 0xffffffff;
633 
634     do {
635 	done = 1;
636 	ret = init_as_req (context,
637 			   opts,
638 			   creds,
639 			   addrs,
640 			   etypes,
641 			   ptypes,
642 			   preauth,
643 			   key_proc,
644 			   keyseed,
645 			   nonce,
646 			   &a);
647 	if (my_preauth) {
648 	    free_ETYPE_INFO(&my_preauth->val[0].info);
649 	    free (my_preauth->val);
650 	}
651 	if (ret)
652 	    return ret;
653 
654 	ret = encode_AS_REQ ((unsigned char*)buf + sizeof(buf) - 1,
655 			     sizeof(buf),
656 			     &a,
657 			     &req.length);
658 	free_AS_REQ(&a);
659 	if (ret)
660 	    return ret;
661 
662 	req.data = buf + sizeof(buf) - req.length;
663 
664 	ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
665 	if (ret)
666 	    return ret;
667 
668 	memset (&rep, 0, sizeof(rep));
669 	ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
670 	if(ret) {
671 	    /* let's try to parse it as a KRB-ERROR */
672 	    KRB_ERROR error;
673 	    int ret2;
674 
675 	    ret2 = krb5_rd_error(context, &resp, &error);
676 	    if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
677 		ret = KRB5KRB_AP_ERR_V4_REPLY;
678 	    krb5_data_free(&resp);
679 	    if (ret2 == 0) {
680 		ret = error.error_code;
681 		/* if no preauth was set and KDC requires it, give it
682                    one more try */
683 		if (!ptypes && !preauth
684 		    && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
685 #if 0
686 			|| ret == KRB5KDC_ERR_BADOPTION
687 #endif
688 		    && set_ptypes(context, &error, &ptypes, &my_preauth)) {
689 		    done = 0;
690 		    preauth = my_preauth;
691 		    free_KRB_ERROR(&error);
692 		    continue;
693 		}
694 		if(ret_as_reply)
695 		    ret_as_reply->error = error;
696 		else
697 		    free_KRB_ERROR (&error);
698 		return ret;
699 	    }
700 	    return ret;
701 	}
702 	krb5_data_free(&resp);
703     } while(!done);
704 
705     pa = NULL;
706     etype = rep.kdc_rep.enc_part.etype;
707     if(rep.kdc_rep.padata){
708 	int index = 0;
709 	pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
710 			      pa_pw_salt, &index);
711 	if(pa == NULL) {
712 	    index = 0;
713 	    pa = krb5_find_padata(rep.kdc_rep.padata->val,
714 				  rep.kdc_rep.padata->len,
715 				  pa_afs3_salt, &index);
716 	}
717     }
718     if(pa) {
719 	salt.salttype = pa->padata_type;
720 	salt.saltvalue = pa->padata_value;
721 
722 	ret = (*key_proc)(context, etype, salt, keyseed, &key);
723     } else {
724 	/* make a v5 salted pa-data */
725 	ret = krb5_get_pw_salt (context, creds->client, &salt);
726 
727 	if (ret)
728 	    goto out;
729 	ret = (*key_proc)(context, etype, salt, keyseed, &key);
730 	krb5_free_salt(context, salt);
731     }
732     if (ret)
733 	goto out;
734 
735     ret = _krb5_extract_ticket(context,
736 			       &rep,
737 			       creds,
738 			       key,
739 			       keyseed,
740 			       KRB5_KU_AS_REP_ENC_PART,
741 			       NULL,
742 			       nonce,
743 			       FALSE,
744 			       decrypt_proc,
745 			       decryptarg);
746     memset (key->keyvalue.data, 0, key->keyvalue.length);
747     krb5_free_keyblock_contents (context, key);
748     free (key);
749 
750 out:
751     if (ret == 0 && ret_as_reply)
752 	*ret_as_reply = rep;
753     else
754 	krb5_free_kdc_rep (context, &rep);
755     return ret;
756 }
757 
758 krb5_error_code
759 krb5_get_in_tkt(krb5_context context,
760 		krb5_flags options,
761 		const krb5_addresses *addrs,
762 		const krb5_enctype *etypes,
763 		const krb5_preauthtype *ptypes,
764 		krb5_key_proc key_proc,
765 		krb5_const_pointer keyseed,
766 		krb5_decrypt_proc decrypt_proc,
767 		krb5_const_pointer decryptarg,
768 		krb5_creds *creds,
769 		krb5_ccache ccache,
770 		krb5_kdc_rep *ret_as_reply)
771 {
772     krb5_error_code ret;
773     krb5_kdc_flags opts;
774     opts.i = 0;
775     opts.b = int2KDCOptions(options);
776 
777     ret = krb5_get_in_cred (context,
778 			    opts.i,
779 			    addrs,
780 			    etypes,
781 			    ptypes,
782 			    NULL,
783 			    key_proc,
784 			    keyseed,
785 			    decrypt_proc,
786 			    decryptarg,
787 			    creds,
788 			    ret_as_reply);
789     if(ret)
790 	return ret;
791     ret = krb5_cc_store_cred (context, ccache, creds);
792     krb5_free_creds_contents (context, creds);
793     return ret;
794 }
795