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