xref: /freebsd/crypto/heimdal/lib/krb5/get_in_tkt.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
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.97 2000/08/18 06:47:54 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     ret = krb5_crypto_init(context, key, 0, &crypto);
89     if (ret)
90 	return ret;
91 
92     ret = krb5_decrypt_EncryptedData (context,
93 				      crypto,
94 				      usage,
95 				      &dec_rep->kdc_rep.enc_part,
96 				      &data);
97     krb5_crypto_destroy(context, crypto);
98 
99     if (ret)
100 	return ret;
101 
102     ret = krb5_decode_EncASRepPart(context,
103 				   data.data,
104 				   data.length,
105 				   &dec_rep->enc_part,
106 				   &size);
107     if (ret)
108 	ret = krb5_decode_EncTGSRepPart(context,
109 					data.data,
110 					data.length,
111 					&dec_rep->enc_part,
112 					&size);
113     krb5_data_free (&data);
114     if (ret)
115 	return ret;
116     return 0;
117 }
118 
119 int
120 _krb5_extract_ticket(krb5_context context,
121 		     krb5_kdc_rep *rep,
122 		     krb5_creds *creds,
123 		     krb5_keyblock *key,
124 		     krb5_const_pointer keyseed,
125 		     krb5_key_usage key_usage,
126 		     krb5_addresses *addrs,
127 		     unsigned nonce,
128 		     krb5_boolean allow_server_mismatch,
129 		     krb5_boolean ignore_cname,
130 		     krb5_decrypt_proc decrypt_proc,
131 		     krb5_const_pointer decryptarg)
132 {
133     krb5_error_code ret;
134     krb5_principal tmp_principal;
135     int tmp;
136     time_t tmp_time;
137     krb5_timestamp sec_now;
138 
139     ret = principalname2krb5_principal (&tmp_principal,
140 					rep->kdc_rep.cname,
141 					rep->kdc_rep.crealm);
142     if (ret)
143 	goto out;
144 
145     /* compare client */
146 
147     if (!ignore_cname) {
148 	tmp = krb5_principal_compare (context, tmp_principal, creds->client);
149 	if (!tmp) {
150 	    krb5_free_principal (context, tmp_principal);
151 	    ret = KRB5KRB_AP_ERR_MODIFIED;
152 	    goto out;
153 	}
154     }
155 
156     krb5_free_principal (context, creds->client);
157     creds->client = tmp_principal;
158 
159     /* extract ticket */
160     {
161 	unsigned char *buf;
162 	size_t len;
163 	len = length_Ticket(&rep->kdc_rep.ticket);
164 	buf = malloc(len);
165 	if(buf == NULL) {
166 	    ret = ENOMEM;
167 	    goto out;
168 	}
169 	encode_Ticket(buf + len - 1, len, &rep->kdc_rep.ticket, &len);
170 	creds->ticket.data = buf;
171 	creds->ticket.length = len;
172 	creds->second_ticket.length = 0;
173 	creds->second_ticket.data   = NULL;
174     }
175 
176     /* compare server */
177 
178     ret = principalname2krb5_principal (&tmp_principal,
179 					rep->kdc_rep.ticket.sname,
180 					rep->kdc_rep.ticket.realm);
181     if (ret)
182 	goto out;
183     if(allow_server_mismatch){
184 	krb5_free_principal(context, creds->server);
185 	creds->server = tmp_principal;
186 	tmp_principal = NULL;
187     }else{
188 	tmp = krb5_principal_compare (context, tmp_principal, creds->server);
189 	krb5_free_principal (context, tmp_principal);
190 	if (!tmp) {
191 	    ret = KRB5KRB_AP_ERR_MODIFIED;
192 	    goto out;
193 	}
194     }
195 
196     /* decrypt */
197 
198     if (decrypt_proc == NULL)
199 	decrypt_proc = decrypt_tkt;
200 
201     ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
202     if (ret)
203 	goto out;
204 
205 #if 0
206     /* XXX should this decode be here, or in the decrypt_proc? */
207     ret = krb5_decode_keyblock(context, &rep->enc_part.key, 1);
208     if(ret)
209 	goto out;
210 #endif
211 
212     /* compare nonces */
213 
214     if (nonce != rep->enc_part.nonce) {
215 	ret = KRB5KRB_AP_ERR_MODIFIED;
216 	goto out;
217     }
218 
219     /* set kdc-offset */
220 
221     krb5_timeofday (context, &sec_now);
222     if (context->kdc_sec_offset == 0
223 	&& krb5_config_get_bool (context, NULL,
224 				 "libdefaults",
225 				 "kdc_timesync",
226 				 NULL)) {
227 	context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
228 	krb5_timeofday (context, &sec_now);
229     }
230 
231     /* check all times */
232 
233     if (rep->enc_part.starttime) {
234 	tmp_time = *rep->enc_part.starttime;
235     } else
236 	tmp_time = rep->enc_part.authtime;
237 
238     if (creds->times.starttime == 0
239 	&& abs(tmp_time - sec_now) > context->max_skew) {
240 	ret = KRB5KRB_AP_ERR_SKEW;
241 	goto out;
242     }
243 
244     if (creds->times.starttime != 0
245 	&& tmp_time != creds->times.starttime) {
246 	ret = KRB5KRB_AP_ERR_MODIFIED;
247 	goto out;
248     }
249 
250     creds->times.starttime = tmp_time;
251 
252     if (rep->enc_part.renew_till) {
253 	tmp_time = *rep->enc_part.renew_till;
254     } else
255 	tmp_time = 0;
256 
257     if (creds->times.renew_till != 0
258 	&& tmp_time > creds->times.renew_till) {
259 	ret = KRB5KRB_AP_ERR_MODIFIED;
260 	goto out;
261     }
262 
263     creds->times.renew_till = tmp_time;
264 
265     creds->times.authtime = rep->enc_part.authtime;
266 
267     if (creds->times.endtime != 0
268 	&& rep->enc_part.endtime > creds->times.endtime) {
269 	ret = KRB5KRB_AP_ERR_MODIFIED;
270 	goto out;
271     }
272 
273     creds->times.endtime  = rep->enc_part.endtime;
274 
275     if(rep->enc_part.caddr)
276 	krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
277     else if(addrs)
278 	krb5_copy_addresses (context, addrs, &creds->addresses);
279     else {
280 	creds->addresses.len = 0;
281 	creds->addresses.val = NULL;
282     }
283     creds->flags.b = rep->enc_part.flags;
284 
285     creds->authdata.len = 0;
286     creds->authdata.val = NULL;
287     creds->session.keyvalue.length = 0;
288     creds->session.keyvalue.data   = NULL;
289     creds->session.keytype = rep->enc_part.key.keytype;
290     ret = krb5_data_copy (&creds->session.keyvalue,
291 			  rep->enc_part.key.keyvalue.data,
292 			  rep->enc_part.key.keyvalue.length);
293 
294 out:
295     memset (rep->enc_part.key.keyvalue.data, 0,
296 	    rep->enc_part.key.keyvalue.length);
297     return ret;
298 }
299 
300 
301 static krb5_error_code
302 make_pa_enc_timestamp(krb5_context context, PA_DATA *pa,
303 		      krb5_enctype etype, krb5_keyblock *key)
304 {
305     PA_ENC_TS_ENC p;
306     u_char buf[1024];
307     size_t len;
308     EncryptedData encdata;
309     krb5_error_code ret;
310     int32_t sec, usec;
311     int usec2;
312     krb5_crypto crypto;
313 
314     krb5_us_timeofday (context, &sec, &usec);
315     p.patimestamp = sec;
316     usec2         = usec;
317     p.pausec      = &usec2;
318 
319     ret = encode_PA_ENC_TS_ENC(buf + sizeof(buf) - 1,
320 			       sizeof(buf),
321 			       &p,
322 			       &len);
323     if (ret)
324 	return ret;
325 
326     ret = krb5_crypto_init(context, key, 0, &crypto);
327     if (ret)
328 	return ret;
329     ret = krb5_encrypt_EncryptedData(context,
330 				     crypto,
331 				     KRB5_KU_PA_ENC_TIMESTAMP,
332 				     buf + sizeof(buf) - len,
333 				     len,
334 				     0,
335 				     &encdata);
336     krb5_crypto_destroy(context, crypto);
337     if (ret)
338 	return ret;
339 
340     ret = encode_EncryptedData(buf + sizeof(buf) - 1,
341 			       sizeof(buf),
342 			       &encdata,
343 			       &len);
344     free_EncryptedData(&encdata);
345     if (ret)
346 	return ret;
347     pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP;
348     pa->padata_value.length = 0;
349     krb5_data_copy(&pa->padata_value,
350 		   buf + sizeof(buf) - len,
351 		   len);
352     return 0;
353 }
354 
355 static krb5_error_code
356 add_padata(krb5_context context,
357 	   METHOD_DATA *md,
358 	   krb5_principal client,
359 	   krb5_key_proc key_proc,
360 	   krb5_const_pointer keyseed,
361 	   int *enctypes,
362 	   unsigned netypes,
363 	   krb5_salt *salt)
364 {
365     krb5_error_code ret;
366     PA_DATA *pa2;
367     krb5_salt salt2;
368     int *ep;
369     int i;
370 
371     if(salt == NULL) {
372 	/* default to standard salt */
373 	ret = krb5_get_pw_salt (context, client, &salt2);
374 	salt = &salt2;
375     }
376     if (!enctypes) {
377 	enctypes = (int *)context->etypes; /* XXX */
378 	netypes = 0;
379 	for (ep = enctypes; *ep != ETYPE_NULL; ep++)
380 	    netypes++;
381     }
382     pa2 = realloc (md->val, (md->len + netypes) * sizeof(*md->val));
383     if (pa2 == NULL)
384 	return ENOMEM;
385     md->val = pa2;
386 
387     for (i = 0; i < netypes; ++i) {
388 	krb5_keyblock *key;
389 
390 	ret = (*key_proc)(context, enctypes[i], *salt, keyseed, &key);
391 	if (ret)
392 	    continue;
393 	ret = make_pa_enc_timestamp (context, &md->val[md->len],
394 				     enctypes[i], key);
395 	krb5_free_keyblock (context, key);
396 	if (ret)
397 	    return ret;
398 	++md->len;
399     }
400     if(salt == &salt2)
401 	krb5_free_salt(context, salt2);
402     return 0;
403 }
404 
405 static krb5_error_code
406 init_as_req (krb5_context context,
407 	     krb5_kdc_flags opts,
408 	     krb5_creds *creds,
409 	     const krb5_addresses *addrs,
410 	     const krb5_enctype *etypes,
411 	     const krb5_preauthtype *ptypes,
412 	     const krb5_preauthdata *preauth,
413 	     krb5_key_proc key_proc,
414 	     krb5_const_pointer keyseed,
415 	     unsigned nonce,
416 	     AS_REQ *a)
417 {
418     krb5_error_code ret;
419     krb5_salt salt;
420 
421     memset(a, 0, sizeof(*a));
422 
423     a->pvno = 5;
424     a->msg_type = krb_as_req;
425     a->req_body.kdc_options = opts.b;
426     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
427     if (a->req_body.cname == NULL) {
428 	ret = ENOMEM;
429 	goto fail;
430     }
431     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
432     if (a->req_body.sname == NULL) {
433 	ret = ENOMEM;
434 	goto fail;
435     }
436     ret = krb5_principal2principalname (a->req_body.cname, creds->client);
437     if (ret)
438 	goto fail;
439     ret = krb5_principal2principalname (a->req_body.sname, creds->server);
440     if (ret)
441 	goto fail;
442     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
443     if (ret)
444 	goto fail;
445 
446     if(creds->times.starttime) {
447 	a->req_body.from = malloc(sizeof(*a->req_body.from));
448 	if (a->req_body.from == NULL) {
449 	    ret = ENOMEM;
450 	    goto fail;
451 	}
452 	*a->req_body.from = creds->times.starttime;
453     }
454     if(creds->times.endtime){
455 	ALLOC(a->req_body.till, 1);
456 	*a->req_body.till = creds->times.endtime;
457     }
458     if(creds->times.renew_till){
459 	a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
460 	if (a->req_body.rtime == NULL) {
461 	    ret = ENOMEM;
462 	    goto fail;
463 	}
464 	*a->req_body.rtime = creds->times.renew_till;
465     }
466     a->req_body.nonce = nonce;
467     ret = krb5_init_etype (context,
468 			   &a->req_body.etype.len,
469 			   &a->req_body.etype.val,
470 			   etypes);
471     if (ret)
472 	goto fail;
473 
474     /*
475      * This means no addresses
476      */
477 
478     if (addrs && addrs->len == 0) {
479 	a->req_body.addresses = NULL;
480     } else {
481 	a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
482 	if (a->req_body.addresses == NULL) {
483 	    ret = ENOMEM;
484 	    goto fail;
485 	}
486 
487 	if (addrs)
488 	    ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
489 	else
490 	    ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
491 	if (ret)
492 	    return ret;
493     }
494 
495     a->req_body.enc_authorization_data = NULL;
496     a->req_body.additional_tickets = NULL;
497 
498     if(preauth != NULL) {
499 	int i;
500 	ALLOC(a->padata, 1);
501 	if(a->padata == NULL) {
502 	    ret = ENOMEM;
503 	    goto fail;
504 	}
505 	for(i = 0; i < preauth->len; i++) {
506 	    if(preauth->val[i].type == KRB5_PADATA_ENC_TIMESTAMP){
507 		int j;
508 		PA_DATA *tmp = realloc(a->padata->val,
509 				       (a->padata->len +
510 					preauth->val[i].info.len) *
511 				       sizeof(*a->padata->val));
512 		if(tmp == NULL) {
513 		    ret = ENOMEM;
514 		    goto fail;
515 		}
516 		a->padata->val = tmp;
517 		for(j = 0; j < preauth->val[i].info.len; j++) {
518 		    krb5_salt *sp = &salt;
519 		    if(preauth->val[i].info.val[j].salttype)
520 			salt.salttype = *preauth->val[i].info.val[j].salttype;
521 		    else
522 			salt.salttype = KRB5_PW_SALT;
523 		    if(preauth->val[i].info.val[j].salt)
524 			salt.saltvalue = *preauth->val[i].info.val[j].salt;
525 		    else
526 			if(salt.salttype == KRB5_PW_SALT)
527 			    sp = NULL;
528 			else
529 			    krb5_data_zero(&salt.saltvalue);
530 		    add_padata(context, a->padata, creds->client,
531 			       key_proc, keyseed,
532 			       &preauth->val[i].info.val[j].etype, 1,
533 			       sp);
534 		}
535 	    }
536 	}
537     } else
538     /* not sure this is the way to use `ptypes' */
539     if (ptypes == NULL || *ptypes == KRB5_PADATA_NONE)
540 	a->padata = NULL;
541     else if (*ptypes ==  KRB5_PADATA_ENC_TIMESTAMP) {
542 	ALLOC(a->padata, 1);
543 	if (a->padata == NULL) {
544 	    ret = ENOMEM;
545 	    goto fail;
546 	}
547 	a->padata->len = 0;
548 	a->padata->val = NULL;
549 
550 	/* make a v5 salted pa-data */
551 	add_padata(context, a->padata, creds->client,
552 		   key_proc, keyseed, a->req_body.etype.val,
553 		   a->req_body.etype.len, NULL);
554 
555 	/* make a v4 salted pa-data */
556 	salt.salttype = KRB5_PW_SALT;
557 	krb5_data_zero(&salt.saltvalue);
558 	add_padata(context, a->padata, creds->client,
559 		   key_proc, keyseed, a->req_body.etype.val,
560 		   a->req_body.etype.len, &salt);
561     } else {
562 	ret = KRB5_PREAUTH_BAD_TYPE;
563 	goto fail;
564     }
565     return 0;
566 fail:
567     free_AS_REQ(a);
568     return ret;
569 }
570 
571 static int
572 set_ptypes(krb5_context context,
573 	   KRB_ERROR *error,
574 	   krb5_preauthtype **ptypes,
575 	   krb5_preauthdata **preauth)
576 {
577     static krb5_preauthdata preauth2;
578     static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };
579 
580     if(error->e_data) {
581 	METHOD_DATA md;
582 	int i;
583 	decode_METHOD_DATA(error->e_data->data,
584 			   error->e_data->length,
585 			   &md,
586 			   NULL);
587 	for(i = 0; i < md.len; i++){
588 	    switch(md.val[i].padata_type){
589 	    case KRB5_PADATA_ENC_TIMESTAMP:
590 		*ptypes = ptypes2;
591 		break;
592 	    case KRB5_PADATA_ETYPE_INFO:
593 		*preauth = &preauth2;
594 		ALLOC_SEQ(*preauth, 1);
595 		(*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
596 		krb5_decode_ETYPE_INFO(context,
597 				       md.val[i].padata_value.data,
598 				       md.val[i].padata_value.length,
599 				       &(*preauth)->val[0].info,
600 				       NULL);
601 		break;
602 	    default:
603 		break;
604 	    }
605 	}
606 	free_METHOD_DATA(&md);
607     } else {
608 	*ptypes = ptypes2;
609     }
610     return(1);
611 }
612 
613 krb5_error_code
614 krb5_get_in_cred(krb5_context context,
615 		 krb5_flags options,
616 		 const krb5_addresses *addrs,
617 		 const krb5_enctype *etypes,
618 		 const krb5_preauthtype *ptypes,
619 		 const krb5_preauthdata *preauth,
620 		 krb5_key_proc key_proc,
621 		 krb5_const_pointer keyseed,
622 		 krb5_decrypt_proc decrypt_proc,
623 		 krb5_const_pointer decryptarg,
624 		 krb5_creds *creds,
625 		 krb5_kdc_rep *ret_as_reply)
626 {
627     krb5_error_code ret;
628     AS_REQ a;
629     krb5_kdc_rep rep;
630     krb5_data req, resp;
631     char buf[BUFSIZ];
632     krb5_salt salt;
633     krb5_keyblock *key;
634     size_t size;
635     krb5_kdc_flags opts;
636     PA_DATA *pa;
637     krb5_enctype etype;
638     krb5_preauthdata *my_preauth = NULL;
639     unsigned nonce;
640     int done;
641 
642     opts.i = options;
643 
644     krb5_generate_random_block (&nonce, sizeof(nonce));
645     nonce &= 0xffffffff;
646 
647     do {
648 	done = 1;
649 	ret = init_as_req (context,
650 			   opts,
651 			   creds,
652 			   addrs,
653 			   etypes,
654 			   ptypes,
655 			   preauth,
656 			   key_proc,
657 			   keyseed,
658 			   nonce,
659 			   &a);
660 	if (my_preauth) {
661 	    free_ETYPE_INFO(&my_preauth->val[0].info);
662 	    free (my_preauth->val);
663 	}
664 	if (ret)
665 	    return ret;
666 
667 	ret = encode_AS_REQ ((unsigned char*)buf + sizeof(buf) - 1,
668 			     sizeof(buf),
669 			     &a,
670 			     &req.length);
671 	free_AS_REQ(&a);
672 	if (ret)
673 	    return ret;
674 
675 	req.data = buf + sizeof(buf) - req.length;
676 
677 	ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
678 	if (ret)
679 	    return ret;
680 
681 	memset (&rep, 0, sizeof(rep));
682 	ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
683 	if(ret) {
684 	    /* let's try to parse it as a KRB-ERROR */
685 	    KRB_ERROR error;
686 	    int ret2;
687 
688 	    ret2 = krb5_rd_error(context, &resp, &error);
689 	    if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
690 		ret = KRB5KRB_AP_ERR_V4_REPLY;
691 	    krb5_data_free(&resp);
692 	    if (ret2 == 0) {
693 		ret = error.error_code;
694 		/* if no preauth was set and KDC requires it, give it
695                    one more try */
696 		if (!ptypes && !preauth
697 		    && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
698 #if 0
699 			|| ret == KRB5KDC_ERR_BADOPTION
700 #endif
701 		    && set_ptypes(context, &error, &ptypes, &my_preauth)) {
702 		    done = 0;
703 		    preauth = my_preauth;
704 		    free_KRB_ERROR(&error);
705 		    continue;
706 		}
707 		if(ret_as_reply)
708 		    ret_as_reply->error = error;
709 		else
710 		    free_KRB_ERROR (&error);
711 		return ret;
712 	    }
713 	    return ret;
714 	}
715 	krb5_data_free(&resp);
716     } while(!done);
717 
718     pa = NULL;
719     etype = rep.kdc_rep.enc_part.etype;
720     if(rep.kdc_rep.padata){
721 	int index = 0;
722 	pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len,
723 			      KRB5_PADATA_PW_SALT, &index);
724 	if(pa == NULL) {
725 	    index = 0;
726 	    pa = krb5_find_padata(rep.kdc_rep.padata->val,
727 				  rep.kdc_rep.padata->len,
728 				  KRB5_PADATA_AFS3_SALT, &index);
729 	}
730     }
731     if(pa) {
732 	salt.salttype = pa->padata_type;
733 	salt.saltvalue = pa->padata_value;
734 
735 	ret = (*key_proc)(context, etype, salt, keyseed, &key);
736     } else {
737 	/* make a v5 salted pa-data */
738 	ret = krb5_get_pw_salt (context, creds->client, &salt);
739 
740 	if (ret)
741 	    goto out;
742 	ret = (*key_proc)(context, etype, salt, keyseed, &key);
743 	krb5_free_salt(context, salt);
744     }
745     if (ret)
746 	goto out;
747 
748     ret = _krb5_extract_ticket(context,
749 			       &rep,
750 			       creds,
751 			       key,
752 			       keyseed,
753 			       KRB5_KU_AS_REP_ENC_PART,
754 			       NULL,
755 			       nonce,
756 			       FALSE,
757 			       opts.b.request_anonymous,
758 			       decrypt_proc,
759 			       decryptarg);
760     memset (key->keyvalue.data, 0, key->keyvalue.length);
761     krb5_free_keyblock_contents (context, key);
762     free (key);
763 
764 out:
765     if (ret == 0 && ret_as_reply)
766 	*ret_as_reply = rep;
767     else
768 	krb5_free_kdc_rep (context, &rep);
769     return ret;
770 }
771 
772 krb5_error_code
773 krb5_get_in_tkt(krb5_context context,
774 		krb5_flags options,
775 		const krb5_addresses *addrs,
776 		const krb5_enctype *etypes,
777 		const krb5_preauthtype *ptypes,
778 		krb5_key_proc key_proc,
779 		krb5_const_pointer keyseed,
780 		krb5_decrypt_proc decrypt_proc,
781 		krb5_const_pointer decryptarg,
782 		krb5_creds *creds,
783 		krb5_ccache ccache,
784 		krb5_kdc_rep *ret_as_reply)
785 {
786     krb5_error_code ret;
787     krb5_kdc_flags opts;
788     opts.i = 0;
789     opts.b = int2KDCOptions(options);
790 
791     ret = krb5_get_in_cred (context,
792 			    opts.i,
793 			    addrs,
794 			    etypes,
795 			    ptypes,
796 			    NULL,
797 			    key_proc,
798 			    keyseed,
799 			    decrypt_proc,
800 			    decryptarg,
801 			    creds,
802 			    ret_as_reply);
803     if(ret)
804 	return ret;
805     ret = krb5_cc_store_cred (context, ccache, creds);
806     krb5_free_creds_contents (context, creds);
807     return ret;
808 }
809