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