r18826: Allow 'enterprise' principal names to log in.
[amitay/samba.git] / source4 / heimdal / kdc / kerberos5.c
1 /*
2  * Copyright (c) 1997-2005 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 "kdc_locl.h"
35
36 RCSID("$Id: kerberos5.c,v 1.211 2006/04/27 12:01:09 lha Exp $");
37
38 #define MAX_TIME ((time_t)((1U << 31) - 1))
39
40 static void
41 fix_time(time_t **t)
42 {
43     if(*t == NULL){
44         ALLOC(*t);
45         **t = MAX_TIME;
46     }
47     if(**t == 0) **t = MAX_TIME; /* fix for old clients */
48 }
49
50 static int
51 realloc_method_data(METHOD_DATA *md)
52 {
53     PA_DATA *pa;
54     pa = realloc(md->val, (md->len + 1) * sizeof(*md->val));
55     if(pa == NULL)
56         return ENOMEM;
57     md->val = pa;
58     md->len++;
59     return 0;
60 }
61
62 static void
63 set_salt_padata (METHOD_DATA *md, Salt *salt)
64 {
65     if (salt) {
66         realloc_method_data(md);
67         md->val[md->len - 1].padata_type = salt->type;
68         copy_octet_string(&salt->salt,
69                           &md->val[md->len - 1].padata_value);
70     }
71 }
72
73 static PA_DATA*
74 find_padata(KDC_REQ *req, int *start, int type)
75 {
76     while(*start < req->padata->len){
77         (*start)++;
78         if(req->padata->val[*start - 1].padata_type == type)
79             return &req->padata->val[*start - 1];
80     }
81     return NULL;
82 }
83
84 /*
85  * return the first appropriate key of `princ' in `ret_key'.  Look for
86  * all the etypes in (`etypes', `len'), stopping as soon as we find
87  * one, but preferring one that has default salt
88  */
89
90 static krb5_error_code
91 find_etype(krb5_context context, const hdb_entry_ex *princ,
92            krb5_enctype *etypes, unsigned len, 
93            Key **ret_key, krb5_enctype *ret_etype)
94 {
95     int i;
96     krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
97
98     for(i = 0; ret != 0 && i < len ; i++) {
99         Key *key = NULL;
100
101         if (krb5_enctype_valid(context, etypes[i]) != 0)
102             continue;
103
104         while (hdb_next_enctype2key(context, &princ->entry, etypes[i], &key) == 0) {
105             if (key->key.keyvalue.length == 0) {
106                 ret = KRB5KDC_ERR_NULL_KEY;
107                 continue;
108             }
109             *ret_key   = key;
110             *ret_etype = etypes[i];
111             ret = 0;
112             if (key->salt == NULL)
113                 return ret;
114         }
115     }
116     return ret;
117 }
118
119 static krb5_error_code
120 find_keys(krb5_context context, 
121           krb5_kdc_configuration *config,
122           const hdb_entry_ex *client,
123           const char *client_name,
124           const hdb_entry_ex *server,
125           const char *server_name,
126           Key **ckey,
127           krb5_enctype *cetype,
128           Key **skey,
129           krb5_enctype *setype, 
130           krb5_enctype *etypes,
131           unsigned num_etypes)
132 {
133     krb5_error_code ret;
134
135     if(client){
136         /* find client key */
137         ret = find_etype(context, client, etypes, num_etypes, ckey, cetype);
138         if (ret) {
139             kdc_log(context, config, 0, 
140                     "Client (%s) has no support for etypes", client_name);
141             return ret;
142         }
143     }
144
145     if(server){
146         /* find server key */
147         ret = find_etype(context, server, etypes, num_etypes, skey, setype);
148         if (ret) {
149             kdc_log(context, config, 0, 
150                     "Server (%s) has no support for etypes", server_name);
151             return ret;
152         }
153     }
154     return 0;
155 }
156
157 static krb5_error_code
158 make_anonymous_principalname (PrincipalName *pn)
159 {
160     pn->name_type = KRB5_NT_PRINCIPAL;
161     pn->name_string.len = 1;
162     pn->name_string.val = malloc(sizeof(*pn->name_string.val));
163     if (pn->name_string.val == NULL)
164         return ENOMEM;
165     pn->name_string.val[0] = strdup("anonymous");
166     if (pn->name_string.val[0] == NULL) {
167         free(pn->name_string.val);
168         pn->name_string.val = NULL;
169         return ENOMEM;
170     }
171     return 0;
172 }
173
174 static void
175 log_timestamp(krb5_context context, 
176               krb5_kdc_configuration *config,
177               const char *type,
178               KerberosTime authtime, KerberosTime *starttime, 
179               KerberosTime endtime, KerberosTime *renew_till)
180 {
181     char authtime_str[100], starttime_str[100], 
182         endtime_str[100], renewtime_str[100];
183     
184     krb5_format_time(context, authtime, 
185                      authtime_str, sizeof(authtime_str), TRUE); 
186     if (starttime)
187         krb5_format_time(context, *starttime, 
188                          starttime_str, sizeof(starttime_str), TRUE); 
189     else
190         strlcpy(starttime_str, "unset", sizeof(starttime_str));
191     krb5_format_time(context, endtime, 
192                      endtime_str, sizeof(endtime_str), TRUE); 
193     if (renew_till)
194         krb5_format_time(context, *renew_till, 
195                          renewtime_str, sizeof(renewtime_str), TRUE); 
196     else
197         strlcpy(renewtime_str, "unset", sizeof(renewtime_str));
198     
199     kdc_log(context, config, 5,
200             "%s authtime: %s starttime: %s endtime: %s renew till: %s",
201             type, authtime_str, starttime_str, endtime_str, renewtime_str);
202 }
203
204 static void
205 log_patypes(krb5_context context, 
206             krb5_kdc_configuration *config,
207             METHOD_DATA *padata)
208 {
209     struct rk_strpool *p = NULL;
210     char *str;
211     int i;
212             
213     for (i = 0; i < padata->len; i++) {
214         switch(padata->val[i].padata_type) {
215         case KRB5_PADATA_PK_AS_REQ:
216             p = rk_strpoolprintf(p, "PK-INIT(ietf)");
217             break;
218         case KRB5_PADATA_PK_AS_REQ_WIN:
219             p = rk_strpoolprintf(p, "PK-INIT(win2k)");
220             break;
221         case KRB5_PADATA_PA_PK_OCSP_RESPONSE:
222             p = rk_strpoolprintf(p, "OCSP");
223             break;
224         case KRB5_PADATA_ENC_TIMESTAMP:
225             p = rk_strpoolprintf(p, "encrypted-timestamp");
226             break;
227         default:
228             p = rk_strpoolprintf(p, "%d", padata->val[i].padata_type);
229             break;
230         }
231         if (p && i + 1 < padata->len)
232             p = rk_strpoolprintf(p, ", ");
233         if (p == NULL) {
234             kdc_log(context, config, 0, "out of memory");
235             return;
236         }
237     }
238     if (p == NULL)
239         p = rk_strpoolprintf(p, "none");
240         
241     str = rk_strpoolcollect(p);
242     kdc_log(context, config, 0, "Client sent patypes: %s", str);
243     free(str);
244 }
245
246 /*
247  *
248  */
249
250
251 static krb5_error_code
252 encode_reply(krb5_context context,
253              krb5_kdc_configuration *config,
254              KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, 
255              krb5_enctype etype, 
256              int skvno, EncryptionKey *skey,
257              int ckvno, EncryptionKey *ckey,
258              const char **e_text,
259              krb5_data *reply)
260 {
261     unsigned char *buf;
262     size_t buf_size;
263     size_t len;
264     krb5_error_code ret;
265     krb5_crypto crypto;
266
267     ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret);
268     if(ret) {
269         kdc_log(context, config, 0, "Failed to encode ticket: %s", 
270                 krb5_get_err_text(context, ret));
271         return ret;
272     }
273     if(buf_size != len) {
274         free(buf);
275         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
276         *e_text = "KDC internal error";
277         return KRB5KRB_ERR_GENERIC;
278     }
279
280     ret = krb5_crypto_init(context, skey, etype, &crypto);
281     if (ret) {
282         free(buf);
283         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
284                 krb5_get_err_text(context, ret));
285         return ret;
286     }
287
288     ret = krb5_encrypt_EncryptedData(context, 
289                                      crypto,
290                                      KRB5_KU_TICKET,
291                                      buf,
292                                      len,
293                                      skvno,
294                                      &rep->ticket.enc_part);
295     free(buf);
296     krb5_crypto_destroy(context, crypto);
297     if(ret) {
298         kdc_log(context, config, 0, "Failed to encrypt data: %s",
299                 krb5_get_err_text(context, ret));
300         return ret;
301     }
302     
303     if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep)
304         ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret);
305     else
306         ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret);
307     if(ret) {
308         kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", 
309                 krb5_get_err_text(context, ret));
310         return ret;
311     }
312     if(buf_size != len) {
313         free(buf);
314         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
315         *e_text = "KDC internal error";
316         return KRB5KRB_ERR_GENERIC;
317     }
318     ret = krb5_crypto_init(context, ckey, 0, &crypto);
319     if (ret) {
320         free(buf);
321         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
322                 krb5_get_err_text(context, ret));
323         return ret;
324     }
325     if(rep->msg_type == krb_as_rep) {
326         krb5_encrypt_EncryptedData(context,
327                                    crypto,
328                                    KRB5_KU_AS_REP_ENC_PART,
329                                    buf,
330                                    len,
331                                    ckvno,
332                                    &rep->enc_part);
333         free(buf);
334         ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret);
335     } else {
336         krb5_encrypt_EncryptedData(context,
337                                    crypto,
338                                    KRB5_KU_TGS_REP_ENC_PART_SESSION,
339                                    buf,
340                                    len,
341                                    ckvno,
342                                    &rep->enc_part);
343         free(buf);
344         ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret);
345     }
346     krb5_crypto_destroy(context, crypto);
347     if(ret) {
348         kdc_log(context, config, 0, "Failed to encode KDC-REP: %s", 
349                 krb5_get_err_text(context, ret));
350         return ret;
351     }
352     if(buf_size != len) {
353         free(buf);
354         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
355         *e_text = "KDC internal error";
356         return KRB5KRB_ERR_GENERIC;
357     }
358     reply->data = buf;
359     reply->length = buf_size;
360     return 0;
361 }
362
363 static krb5_error_code
364 make_etype_info_entry(krb5_context context, ETYPE_INFO_ENTRY *ent, Key *key)
365 {
366     ent->etype = key->key.keytype;
367     if(key->salt){
368 #if 0
369         ALLOC(ent->salttype);
370
371         if(key->salt->type == hdb_pw_salt)
372             *ent->salttype = 0; /* or 1? or NULL? */
373         else if(key->salt->type == hdb_afs3_salt)
374             *ent->salttype = 2;
375         else {
376             kdc_log(context, config, 0, "unknown salt-type: %d", 
377                     key->salt->type);
378             return KRB5KRB_ERR_GENERIC;
379         }
380         /* according to `the specs', we can't send a salt if
381            we have AFS3 salted key, but that requires that you
382            *know* what cell you are using (e.g by assuming
383            that the cell is the same as the realm in lower
384            case) */
385 #elif 0
386         ALLOC(ent->salttype);
387         *ent->salttype = key->salt->type;
388 #else
389         /* 
390          * We shouldn't sent salttype since its incompatible with the
391          * specification and its break windows clients.  The afs
392          * salting problem is solved by using KRB5-PADATA-AFS3-SALT
393          * implemented in Heimdal 0.7 and later.
394          */
395         ent->salttype = NULL;
396 #endif
397         krb5_copy_data(context, &key->salt->salt,
398                        &ent->salt);
399     } else {
400         /* we return no salt type at all, as that should indicate
401          * the default salt type and make everybody happy.  some
402          * systems (like w2k) dislike being told the salt type
403          * here. */
404
405         ent->salttype = NULL;
406         ent->salt = NULL;
407     }
408     return 0;
409 }
410
411 static krb5_error_code
412 get_pa_etype_info(krb5_context context, 
413                   krb5_kdc_configuration *config,
414                   METHOD_DATA *md, hdb_entry *client, 
415                   ENCTYPE *etypes, unsigned int etypes_len)
416 {
417     krb5_error_code ret = 0;
418     int i, j;
419     unsigned int n = 0;
420     ETYPE_INFO pa;
421     unsigned char *buf;
422     size_t len;
423     
424
425     pa.len = client->keys.len;
426     if(pa.len > UINT_MAX/sizeof(*pa.val))
427         return ERANGE;
428     pa.val = malloc(pa.len * sizeof(*pa.val));
429     if(pa.val == NULL)
430         return ENOMEM;
431     memset(pa.val, 0, pa.len * sizeof(*pa.val));
432
433     for(j = 0; j < etypes_len; j++) {
434         for (i = 0; i < n; i++)
435             if (pa.val[i].etype == etypes[j])
436                 goto skip1;
437         for(i = 0; i < client->keys.len; i++) {
438             if(client->keys.val[i].key.keytype == etypes[j]) {
439                 if (krb5_enctype_valid(context, etypes[j]) != 0)
440                     continue;
441                 if((ret = make_etype_info_entry(context, 
442                                                 &pa.val[n++], 
443                                                 &client->keys.val[i])) != 0) {
444                     free_ETYPE_INFO(&pa);
445                     return ret;
446                 }
447             }
448         }
449     skip1:;
450     }
451     for(i = 0; i < client->keys.len; i++) {
452         for(j = 0; j < etypes_len; j++) {
453             if(client->keys.val[i].key.keytype == etypes[j])
454                 goto skip2;
455         }
456         if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
457             continue;
458         if((ret = make_etype_info_entry(context, 
459                                         &pa.val[n++], 
460                                         &client->keys.val[i])) != 0) {
461             free_ETYPE_INFO(&pa);
462             return ret;
463         }
464     skip2:;
465     }
466     
467     if(n != pa.len) {
468         char *name;
469         ret = krb5_unparse_name(context, client->principal, &name);
470         if (ret)
471             name = "<unparse_name failed>";
472         kdc_log(context, config, 0, "internal error in get_pa_etype_info(%s): %d != %d", 
473                 name, n, pa.len);
474         if (ret == 0)
475             free(name);
476         pa.len = n;
477     }
478
479     ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
480     free_ETYPE_INFO(&pa);
481     if(ret)
482         return ret;
483     ret = realloc_method_data(md);
484     if(ret) {
485         free(buf);
486         return ret;
487     }
488     md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO;
489     md->val[md->len - 1].padata_value.length = len;
490     md->val[md->len - 1].padata_value.data = buf;
491     return 0;
492 }
493
494 /*
495  *
496  */
497
498 extern int _krb5_AES_string_to_default_iterator;
499
500 static krb5_error_code
501 make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key)
502 {
503     ent->etype = key->key.keytype;
504     if(key->salt) {
505         ALLOC(ent->salt);
506         if (ent->salt == NULL)
507             return ENOMEM;
508         *ent->salt = malloc(key->salt->salt.length + 1);
509         if (*ent->salt == NULL) {
510             free(ent->salt);
511             ent->salt = NULL;
512             return ENOMEM;
513         }
514         memcpy(*ent->salt, key->salt->salt.data, key->salt->salt.length);
515         (*ent->salt)[key->salt->salt.length] = '\0';
516     } else
517         ent->salt = NULL;
518
519     ent->s2kparams = NULL;
520
521     switch (key->key.keytype) {
522     case ETYPE_AES128_CTS_HMAC_SHA1_96:
523     case ETYPE_AES256_CTS_HMAC_SHA1_96:
524         ALLOC(ent->s2kparams);
525         if (ent->s2kparams == NULL)
526             return ENOMEM;
527         ent->s2kparams->length = 4;
528         ent->s2kparams->data = malloc(ent->s2kparams->length);
529         if (ent->s2kparams->data == NULL) {
530             free(ent->s2kparams);
531             ent->s2kparams = NULL;
532             return ENOMEM;
533         }
534         _krb5_put_int(ent->s2kparams->data, 
535                       _krb5_AES_string_to_default_iterator, 
536                       ent->s2kparams->length);
537         break;
538     case ETYPE_DES_CBC_CRC:
539     case ETYPE_DES_CBC_MD4:
540     case ETYPE_DES_CBC_MD5:
541         /* Check if this was a AFS3 salted key */
542         if(key->salt && key->salt->type == hdb_afs3_salt){
543             ALLOC(ent->s2kparams);
544             if (ent->s2kparams == NULL)
545                 return ENOMEM;
546             ent->s2kparams->length = 1;
547             ent->s2kparams->data = malloc(ent->s2kparams->length);
548             if (ent->s2kparams->data == NULL) {
549                 free(ent->s2kparams);
550                 ent->s2kparams = NULL;
551                 return ENOMEM;
552             }
553             _krb5_put_int(ent->s2kparams->data, 
554                           1,
555                           ent->s2kparams->length);
556         }
557         break;
558     default:
559         break;
560     }
561     return 0;
562 }
563
564 /*
565  * Return 1 if the client have only older enctypes, this is for
566  * determining if the server should send ETYPE_INFO2 or not.
567  */
568
569 static int
570 only_older_enctype_p(const KDC_REQ *req)
571 {
572     int i;
573
574     for(i = 0; i < req->req_body.etype.len; i++) {
575         switch (req->req_body.etype.val[i]) {
576         case ETYPE_DES_CBC_CRC:
577         case ETYPE_DES_CBC_MD4:
578         case ETYPE_DES_CBC_MD5:
579         case ETYPE_DES3_CBC_SHA1:
580         case ETYPE_ARCFOUR_HMAC_MD5:
581         case ETYPE_ARCFOUR_HMAC_MD5_56:
582             break;
583         default:
584             return 0;
585         }
586     }
587     return 1;
588 }
589
590 /*
591  *
592  */
593
594 static krb5_error_code
595 get_pa_etype_info2(krb5_context context, 
596                    krb5_kdc_configuration *config,
597                    METHOD_DATA *md, hdb_entry *client, 
598                    ENCTYPE *etypes, unsigned int etypes_len)
599 {
600     krb5_error_code ret = 0;
601     int i, j;
602     unsigned int n = 0;
603     ETYPE_INFO2 pa;
604     unsigned char *buf;
605     size_t len;
606
607     pa.len = client->keys.len;
608     if(pa.len > UINT_MAX/sizeof(*pa.val))
609         return ERANGE;
610     pa.val = malloc(pa.len * sizeof(*pa.val));
611     if(pa.val == NULL)
612         return ENOMEM;
613     memset(pa.val, 0, pa.len * sizeof(*pa.val));
614
615     for(j = 0; j < etypes_len; j++) {
616         for (i = 0; i < n; i++)
617             if (pa.val[i].etype == etypes[j])
618                 goto skip1;
619         for(i = 0; i < client->keys.len; i++) {
620             if(client->keys.val[i].key.keytype == etypes[j]) {
621                 if (krb5_enctype_valid(context, etypes[j]) != 0)
622                     continue;
623                 if((ret = make_etype_info2_entry(&pa.val[n++], 
624                                                  &client->keys.val[i])) != 0) {
625                     free_ETYPE_INFO2(&pa);
626                     return ret;
627                 }
628             }
629         }
630     skip1:;
631     }
632     for(i = 0; i < client->keys.len; i++) {
633         for(j = 0; j < etypes_len; j++) {
634             if(client->keys.val[i].key.keytype == etypes[j])
635                 goto skip2;
636         }
637         if (krb5_enctype_valid(context, client->keys.val[i].key.keytype) != 0)
638             continue;
639         if((ret = make_etype_info2_entry(&pa.val[n++],
640                                          &client->keys.val[i])) != 0) {
641             free_ETYPE_INFO2(&pa);
642             return ret;
643         }
644       skip2:;
645     }
646     
647     if(n != pa.len) {
648         char *name;
649         ret = krb5_unparse_name(context, client->principal, &name);
650         if (ret)
651             name = "<unparse_name failed>";
652         kdc_log(context, config, 0,
653                 "internal error in get_pa_etype_info2(%s): %d != %d", 
654                 name, n, pa.len);
655         if (ret == 0)
656             free(name);
657         pa.len = n;
658     }
659
660     ASN1_MALLOC_ENCODE(ETYPE_INFO2, buf, len, &pa, &len, ret);
661     free_ETYPE_INFO2(&pa);
662     if(ret)
663         return ret;
664     ret = realloc_method_data(md);
665     if(ret) {
666         free(buf);
667         return ret;
668     }
669     md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO2;
670     md->val[md->len - 1].padata_value.length = len;
671     md->val[md->len - 1].padata_value.data = buf;
672     return 0;
673 }
674
675 /*
676  * verify the flags on `client' and `server', returning 0
677  * if they are OK and generating an error messages and returning
678  * and error code otherwise.
679  */
680
681 krb5_error_code
682 _kdc_check_flags(krb5_context context, 
683                  krb5_kdc_configuration *config,
684                  hdb_entry_ex *client_ex, const char *client_name,
685                  hdb_entry_ex *server_ex, const char *server_name,
686                  krb5_boolean is_as_req)
687 {
688     if(client_ex != NULL) {
689         hdb_entry *client = &client_ex->entry;
690
691         /* check client */
692         if (client->flags.invalid) {
693             kdc_log(context, config, 0, 
694                     "Client (%s) has invalid bit set", client_name);
695             return KRB5KDC_ERR_POLICY;
696         }
697         
698         if(!client->flags.client){
699             kdc_log(context, config, 0,
700                     "Principal may not act as client -- %s", client_name);
701             return KRB5KDC_ERR_POLICY;
702         }
703         
704         if (client->valid_start && *client->valid_start > kdc_time) {
705             char starttime_str[100];
706             krb5_format_time(context, *client->valid_start, 
707                              starttime_str, sizeof(starttime_str), TRUE); 
708             kdc_log(context, config, 0,
709                     "Client not yet valid until %s -- %s", 
710                     starttime_str, client_name);
711             return KRB5KDC_ERR_CLIENT_NOTYET;
712         }
713         
714         if (client->valid_end && *client->valid_end < kdc_time) {
715             char endtime_str[100];
716             krb5_format_time(context, *client->valid_end, 
717                              endtime_str, sizeof(endtime_str), TRUE); 
718             kdc_log(context, config, 0,
719                     "Client expired at %s -- %s",
720                     endtime_str, client_name);
721             return KRB5KDC_ERR_NAME_EXP;
722         }
723         
724         if (client->pw_end && *client->pw_end < kdc_time 
725             && (server_ex == NULL || !server_ex->entry.flags.change_pw)) {
726             char pwend_str[100];
727             krb5_format_time(context, *client->pw_end, 
728                              pwend_str, sizeof(pwend_str), TRUE); 
729             kdc_log(context, config, 0,
730                     "Client's key has expired at %s -- %s", 
731                     pwend_str, client_name);
732             return KRB5KDC_ERR_KEY_EXPIRED;
733         }
734     }
735
736     /* check server */
737     
738     if (server_ex != NULL) {
739         hdb_entry *server = &server_ex->entry;
740
741         if (server->flags.invalid) {
742             kdc_log(context, config, 0,
743                     "Server has invalid flag set -- %s", server_name);
744             return KRB5KDC_ERR_POLICY;
745         }
746
747         if(!server->flags.server){
748             kdc_log(context, config, 0,
749                     "Principal may not act as server -- %s", server_name);
750             return KRB5KDC_ERR_POLICY;
751         }
752
753         if(!is_as_req && server->flags.initial) {
754             kdc_log(context, config, 0,
755                     "AS-REQ is required for server -- %s", server_name);
756             return KRB5KDC_ERR_POLICY;
757         }
758
759         if (server->valid_start && *server->valid_start > kdc_time) {
760             char starttime_str[100];
761             krb5_format_time(context, *server->valid_start, 
762                              starttime_str, sizeof(starttime_str), TRUE); 
763             kdc_log(context, config, 0,
764                     "Server not yet valid until %s -- %s",
765                     starttime_str, server_name);
766             return KRB5KDC_ERR_SERVICE_NOTYET;
767         }
768
769         if (server->valid_end && *server->valid_end < kdc_time) {
770             char endtime_str[100];
771             krb5_format_time(context, *server->valid_end, 
772                              endtime_str, sizeof(endtime_str), TRUE); 
773             kdc_log(context, config, 0,
774                     "Server expired at %s -- %s", 
775                     endtime_str, server_name);
776             return KRB5KDC_ERR_SERVICE_EXP;
777         }
778
779         if (server->pw_end && *server->pw_end < kdc_time) {
780             char pwend_str[100];
781             krb5_format_time(context, *server->pw_end, 
782                              pwend_str, sizeof(pwend_str), TRUE); 
783             kdc_log(context, config, 0,
784                     "Server's key has expired at -- %s", 
785                     pwend_str, server_name);
786             return KRB5KDC_ERR_KEY_EXPIRED;
787         }
788     }
789     return 0;
790 }
791
792 /*
793  * Return TRUE if `from' is part of `addresses' taking into consideration
794  * the configuration variables that tells us how strict we should be about
795  * these checks
796  */
797
798 static krb5_boolean
799 check_addresses(krb5_context context,        
800                 krb5_kdc_configuration *config,
801                 HostAddresses *addresses, const struct sockaddr *from)
802 {
803     krb5_error_code ret;
804     krb5_address addr;
805     krb5_boolean result;
806     krb5_boolean only_netbios = TRUE;
807     int i;
808     
809     if(config->check_ticket_addresses == 0)
810         return TRUE;
811
812     if(addresses == NULL)
813         return config->allow_null_ticket_addresses;
814     
815     for (i = 0; i < addresses->len; ++i) {
816         if (addresses->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
817             only_netbios = FALSE;
818         }
819     }
820
821     /* Windows sends it's netbios name, which I can only assume is
822      * used for the 'allowed workstations' check.  This is painful,
823      * but we still want to check IP addresses if they happen to be
824      * present.
825      */
826
827     if(only_netbios)
828         return config->allow_null_ticket_addresses;
829
830     ret = krb5_sockaddr2address (context, from, &addr);
831     if(ret)
832         return FALSE;
833
834     result = krb5_address_search(context, &addr, addresses);
835     krb5_free_address (context, &addr);
836     return result;
837 }
838
839 krb5_error_code
840 _kdc_as_rep(krb5_context context, 
841             krb5_kdc_configuration *config,
842             KDC_REQ *req, 
843             const krb5_data *req_buffer, 
844             krb5_data *reply,
845             const char *from,
846             struct sockaddr *from_addr)
847 {
848     KDC_REQ_BODY *b = &req->req_body;
849     AS_REP rep;
850     KDCOptions f = b->kdc_options;
851     hdb_entry_ex *client = NULL, *server = NULL;
852     krb5_enctype cetype, setype;
853     EncTicketPart et;
854     EncKDCRepPart ek;
855     krb5_principal client_princ = NULL, server_princ = NULL;
856     char *client_name = NULL, *server_name = NULL;
857     krb5_error_code ret = 0;
858     const char *e_text = NULL;
859     krb5_crypto crypto;
860     Key *ckey, *skey;
861     EncryptionKey *reply_key;
862 #ifdef PKINIT
863     pk_client_params *pkp = NULL;
864 #endif
865
866     memset(&rep, 0, sizeof(rep));
867
868     if(b->sname == NULL){
869         ret = KRB5KRB_ERR_GENERIC;
870         e_text = "No server in request";
871     } else{
872             _krb5_principalname2krb5_principal (context, &server_princ,
873                                             *(b->sname), b->realm);
874         ret = krb5_unparse_name(context, server_princ, &server_name);
875     }
876     if (ret) {
877         kdc_log(context, config, 0, "AS-REQ malformed server name from %s", from);
878         goto out;
879     }
880     
881     if(b->cname == NULL){
882         ret = KRB5KRB_ERR_GENERIC;
883         e_text = "No client in request";
884     } else {
885             _krb5_principalname2krb5_principal (context, &client_princ,
886                                             *(b->cname), b->realm);
887         ret = krb5_unparse_name(context, client_princ, &client_name);
888     }
889     if (ret) {
890         kdc_log(context, config, 0, "AS-REQ malformed client name from %s", from);
891         goto out;
892     }
893
894     kdc_log(context, config, 0, "AS-REQ %s from %s for %s", 
895             client_name, from, server_name);
896
897     ret = _kdc_db_fetch(context, config, client_princ, 
898                         HDB_F_GET_CLIENT, &client);
899     if(ret){
900         kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name,
901                 krb5_get_err_text(context, ret));
902         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
903         goto out;
904     }
905
906     ret = _kdc_db_fetch(context, config, server_princ,
907                         HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, &server);
908     if(ret){
909         kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name,
910                 krb5_get_err_text(context, ret));
911         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
912         goto out;
913     }
914
915     ret = _kdc_check_flags(context, config, 
916                            client, client_name,
917                            server, server_name,
918                            TRUE);
919     if(ret)
920         goto out;
921
922     if (client->check_client_access) {
923         ret = client->check_client_access(context, client, 
924                                           b->addresses);
925         if(ret)
926             goto out;
927     }
928
929     memset(&et, 0, sizeof(et));
930     memset(&ek, 0, sizeof(ek));
931
932     if(req->padata){
933         int i;
934         PA_DATA *pa;
935         int found_pa = 0;
936
937         log_patypes(context, config, req->padata);
938
939 #ifdef PKINIT
940         kdc_log(context, config, 5, 
941                 "Looking for PKINIT pa-data -- %s", client_name);
942
943         e_text = "No PKINIT PA found";
944
945         i = 0;
946         if ((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ)))
947             ;
948         if (pa == NULL) {
949             i = 0;
950             if((pa = find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN)))
951                 ;
952         }
953         if (pa) {
954             char *client_cert = NULL;
955
956             ret = _kdc_pk_rd_padata(context, config, req, pa, &pkp);
957             if (ret) {
958                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
959                 kdc_log(context, config, 5, 
960                         "Failed to decode PKINIT PA-DATA -- %s", 
961                         client_name);
962                 goto ts_enc;
963             }
964             if (ret == 0 && pkp == NULL)
965                 goto ts_enc;
966
967             ret = _kdc_pk_check_client(context,
968                                        config,
969                                        client_princ, 
970                                        client,
971                                        pkp,
972                                        &client_cert);
973             if (ret) {
974                 e_text = "PKINIT certificate not allowed to "
975                     "impersonate principal";
976                 _kdc_pk_free_client_param(context, pkp);
977
978                 kdc_log(context, config, 0, "%s", e_text);
979                 pkp = NULL;
980                 goto ts_enc;
981             }
982             found_pa = 1;
983             et.flags.pre_authent = 1;
984             kdc_log(context, config, 0,
985                     "PKINIT pre-authentication succeeded -- %s using %s", 
986                     client_name, client_cert);
987             free(client_cert);
988             if (pkp)
989                 goto preauth_done;
990         }
991     ts_enc:
992 #endif
993         kdc_log(context, config, 5, "Looking for ENC-TS pa-data -- %s", 
994                 client_name);
995
996         i = 0;
997         e_text = "No ENC-TS found";
998         while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
999             krb5_data ts_data;
1000             PA_ENC_TS_ENC p;
1001             size_t len;
1002             EncryptedData enc_data;
1003             Key *pa_key;
1004             char *str;
1005             
1006             found_pa = 1;
1007             
1008             ret = decode_EncryptedData(pa->padata_value.data,
1009                                        pa->padata_value.length,
1010                                        &enc_data,
1011                                        &len);
1012             if (ret) {
1013                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1014                 kdc_log(context, config, 5, "Failed to decode PA-DATA -- %s", 
1015                         client_name);
1016                 goto out;
1017             }
1018             
1019             ret = hdb_enctype2key(context, &client->entry, 
1020                                   enc_data.etype, &pa_key);
1021             if(ret){
1022                 char *estr;
1023                 e_text = "No key matches pa-data";
1024                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
1025                 if(krb5_enctype_to_string(context, enc_data.etype, &estr))
1026                     estr = NULL;
1027                 if(estr == NULL)
1028                     kdc_log(context, config, 5, 
1029                             "No client key matching pa-data (%d) -- %s", 
1030                             enc_data.etype, client_name);
1031                 else
1032                     kdc_log(context, config, 5,
1033                             "No client key matching pa-data (%s) -- %s", 
1034                             estr, client_name);
1035                 free(estr);
1036                     
1037                 free_EncryptedData(&enc_data);
1038                 continue;
1039             }
1040
1041         try_next_key:
1042             ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
1043             if (ret) {
1044                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1045                         krb5_get_err_text(context, ret));
1046                 free_EncryptedData(&enc_data);
1047                 continue;
1048             }
1049
1050             ret = krb5_decrypt_EncryptedData (context,
1051                                               crypto,
1052                                               KRB5_KU_PA_ENC_TIMESTAMP,
1053                                               &enc_data,
1054                                               &ts_data);
1055             krb5_crypto_destroy(context, crypto);
1056             if(ret){
1057                 krb5_error_code ret2;
1058                 ret2 = krb5_enctype_to_string(context, 
1059                                              pa_key->key.keytype, &str);
1060                 if (ret2)
1061                     str = NULL;
1062                 kdc_log(context, config, 5, 
1063                         "Failed to decrypt PA-DATA -- %s "
1064                         "(enctype %s) error %s",
1065                         client_name,
1066                         str ? str : "unknown enctype", 
1067                         krb5_get_err_text(context, ret));
1068                 free(str);
1069
1070                 if(hdb_next_enctype2key(context, &client->entry, 
1071                                         enc_data.etype, &pa_key) == 0)
1072                     goto try_next_key;
1073                 e_text = "Failed to decrypt PA-DATA";
1074
1075                 free_EncryptedData(&enc_data);
1076                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1077                 continue;
1078             }
1079             free_EncryptedData(&enc_data);
1080             ret = decode_PA_ENC_TS_ENC(ts_data.data,
1081                                        ts_data.length,
1082                                        &p,
1083                                        &len);
1084             krb5_data_free(&ts_data);
1085             if(ret){
1086                 e_text = "Failed to decode PA-ENC-TS-ENC";
1087                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1088                 kdc_log(context, config, 
1089                         5, "Failed to decode PA-ENC-TS_ENC -- %s",
1090                         client_name);
1091                 continue;
1092             }
1093             free_PA_ENC_TS_ENC(&p);
1094             if (abs(kdc_time - p.patimestamp) > context->max_skew) {
1095                 ret = KRB5KRB_AP_ERR_SKEW;
1096                 kdc_log(context, config, 0,
1097                         "Too large time skew -- %s", client_name);
1098                 /* 
1099                  * the following is needed to make windows clients
1100                  * to retry using the timestamp in the error message
1101                  *
1102                  * this is maybe a bug in windows to not trying when e_text
1103                  * is present...
1104                  */
1105                 e_text = NULL;
1106                 goto out;
1107             }
1108             et.flags.pre_authent = 1;
1109
1110             ret = krb5_enctype_to_string(context,pa_key->key.keytype, &str);
1111             if (ret)
1112                 str = NULL;
1113
1114             kdc_log(context, config, 2,
1115                     "ENC-TS Pre-authentication succeeded -- %s using %s", 
1116                     client_name, str ? str : "unknown enctype");
1117             free(str);
1118             break;
1119         }
1120 #ifdef PKINIT
1121     preauth_done:
1122 #endif
1123         if(found_pa == 0 && config->require_preauth)
1124             goto use_pa;
1125         /* We come here if we found a pa-enc-timestamp, but if there
1126            was some problem with it, other than too large skew */
1127         if(found_pa && et.flags.pre_authent == 0){
1128             kdc_log(context, config, 0, "%s -- %s", e_text, client_name);
1129             e_text = NULL;
1130             goto out;
1131         }
1132     }else if (config->require_preauth
1133               || client->entry.flags.require_preauth
1134               || server->entry.flags.require_preauth) {
1135         METHOD_DATA method_data;
1136         PA_DATA *pa;
1137         unsigned char *buf;
1138         size_t len;
1139         krb5_data foo_data;
1140
1141     use_pa: 
1142         method_data.len = 0;
1143         method_data.val = NULL;
1144
1145         ret = realloc_method_data(&method_data);
1146         pa = &method_data.val[method_data.len-1];
1147         pa->padata_type         = KRB5_PADATA_ENC_TIMESTAMP;
1148         pa->padata_value.length = 0;
1149         pa->padata_value.data   = NULL;
1150
1151 #ifdef PKINIT
1152         ret = realloc_method_data(&method_data);
1153         pa = &method_data.val[method_data.len-1];
1154         pa->padata_type         = KRB5_PADATA_PK_AS_REQ;
1155         pa->padata_value.length = 0;
1156         pa->padata_value.data   = NULL;
1157 #endif
1158
1159         /* 
1160          * RFC4120 requires: 
1161          * - If the client only knows about old enctypes, then send
1162          *   both info replies (we send 'info' first in the list).
1163          * - If the client is 'modern', because it knows about 'new'
1164          *   enctype types, then only send the 'info2' reply.
1165         */
1166
1167         /* XXX check ret */
1168         if (only_older_enctype_p(req))
1169             ret = get_pa_etype_info(context, config,
1170                                     &method_data, &client->entry, 
1171                                     b->etype.val, b->etype.len); 
1172         /* XXX check ret */
1173         ret = get_pa_etype_info2(context, config, &method_data, 
1174                                  &client->entry, b->etype.val, b->etype.len);
1175
1176         
1177         ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
1178         free_METHOD_DATA(&method_data);
1179         foo_data.data   = buf;
1180         foo_data.length = len;
1181         
1182         ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
1183         krb5_mk_error(context,
1184                       ret,
1185                       "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ",
1186                       &foo_data,
1187                       client_princ,
1188                       server_princ,
1189                       NULL,
1190                       NULL,
1191                       reply);
1192         free(buf);
1193         kdc_log(context, config, 0,
1194                 "No preauth found, returning PREAUTH-REQUIRED -- %s",
1195                 client_name);
1196         ret = 0;
1197         goto out2;
1198     }
1199     
1200     ret = find_keys(context, config, 
1201                     client, client_name, 
1202                     server, server_name, 
1203                     &ckey, &cetype, &skey, &setype,
1204                     b->etype.val, b->etype.len);
1205     if(ret)
1206         goto out;
1207         
1208     {
1209         struct rk_strpool *p = NULL;
1210         char *str;
1211         int i;
1212
1213         for (i = 0; i < b->etype.len; i++) {
1214             ret = krb5_enctype_to_string(context, b->etype.val[i], &str);
1215             if (ret == 0) {
1216                 p = rk_strpoolprintf(p, "%s", str);
1217                 free(str);
1218             } else
1219                 p = rk_strpoolprintf(p, "%d", b->etype.val[i]);
1220             if (p && i + 1 < b->etype.len)
1221                 p = rk_strpoolprintf(p, ", ");
1222             if (p == NULL) {
1223                 kdc_log(context, config, 0, "out of memory");
1224                 goto out;
1225             }
1226         }
1227         if (p == NULL)
1228             p = rk_strpoolprintf(p, "no encryption types");
1229
1230         str = rk_strpoolcollect(p);
1231         kdc_log(context, config, 0, "Client supported enctypes: %s", str);
1232         free(str);
1233     }
1234     {
1235         char *cet;
1236         char *set;
1237
1238         ret = krb5_enctype_to_string(context, cetype, &cet);
1239         if(ret == 0) {
1240             ret = krb5_enctype_to_string(context, setype, &set);
1241             if (ret == 0) {
1242                 kdc_log(context, config, 5, "Using %s/%s", cet, set);
1243                 free(set);
1244             }
1245             free(cet);
1246         }
1247         if (ret != 0)
1248             kdc_log(context, config, 5, "Using e-types %d/%d", cetype, setype);
1249     }
1250     
1251     {
1252         char str[128];
1253         unparse_flags(KDCOptions2int(f), asn1_KDCOptions_units(), 
1254                       str, sizeof(str));
1255         if(*str)
1256             kdc_log(context, config, 2, "Requested flags: %s", str);
1257     }
1258     
1259
1260     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
1261        || (f.request_anonymous && !config->allow_anonymous)) {
1262         ret = KRB5KDC_ERR_BADOPTION;
1263         kdc_log(context, config, 0, "Bad KDC options -- %s", client_name);
1264         goto out;
1265     }
1266     
1267     rep.pvno = 5;
1268     rep.msg_type = krb_as_rep;
1269     copy_Realm(&client->entry.principal->realm, &rep.crealm);
1270     if (f.request_anonymous)
1271         make_anonymous_principalname (&rep.cname);
1272     else
1273             _krb5_principal2principalname(&rep.cname, 
1274                                       client->entry.principal);
1275     rep.ticket.tkt_vno = 5;
1276     copy_Realm(&server->entry.principal->realm, &rep.ticket.realm);
1277     _krb5_principal2principalname(&rep.ticket.sname, 
1278                                   server->entry.principal);
1279
1280     et.flags.initial = 1;
1281     if(client->entry.flags.forwardable && server->entry.flags.forwardable)
1282         et.flags.forwardable = f.forwardable;
1283     else if (f.forwardable) {
1284         ret = KRB5KDC_ERR_POLICY;
1285         kdc_log(context, config, 0,
1286                 "Ticket may not be forwardable -- %s", client_name);
1287         goto out;
1288     }
1289     if(client->entry.flags.proxiable && server->entry.flags.proxiable)
1290         et.flags.proxiable = f.proxiable;
1291     else if (f.proxiable) {
1292         ret = KRB5KDC_ERR_POLICY;
1293         kdc_log(context, config, 0, 
1294                 "Ticket may not be proxiable -- %s", client_name);
1295         goto out;
1296     }
1297     if(client->entry.flags.postdate && server->entry.flags.postdate)
1298         et.flags.may_postdate = f.allow_postdate;
1299     else if (f.allow_postdate){
1300         ret = KRB5KDC_ERR_POLICY;
1301         kdc_log(context, config, 0,
1302                 "Ticket may not be postdatable -- %s", client_name);
1303         goto out;
1304     }
1305
1306     /* check for valid set of addresses */
1307     if(!check_addresses(context, config, b->addresses, from_addr)) {
1308         ret = KRB5KRB_AP_ERR_BADADDR;
1309         kdc_log(context, config, 0,
1310                 "Bad address list requested -- %s", client_name);
1311         goto out;
1312     }
1313
1314     krb5_generate_random_keyblock(context, setype, &et.key);
1315     copy_PrincipalName(&rep.cname, &et.cname);
1316     copy_Realm(&rep.crealm, &et.crealm);
1317     
1318     {
1319         time_t start;
1320         time_t t;
1321         
1322         start = et.authtime = kdc_time;
1323     
1324         if(f.postdated && req->req_body.from){
1325             ALLOC(et.starttime);
1326             start = *et.starttime = *req->req_body.from;
1327             et.flags.invalid = 1;
1328             et.flags.postdated = 1; /* XXX ??? */
1329         }
1330         fix_time(&b->till);
1331         t = *b->till;
1332
1333         /* be careful not overflowing */
1334
1335         if(client->entry.max_life)
1336             t = start + min(t - start, *client->entry.max_life);
1337         if(server->entry.max_life)
1338             t = start + min(t - start, *server->entry.max_life);
1339 #if 0
1340         t = min(t, start + realm->max_life);
1341 #endif
1342         et.endtime = t;
1343         if(f.renewable_ok && et.endtime < *b->till){
1344             f.renewable = 1;
1345             if(b->rtime == NULL){
1346                 ALLOC(b->rtime);
1347                 *b->rtime = 0;
1348             }
1349             if(*b->rtime < *b->till)
1350                 *b->rtime = *b->till;
1351         }
1352         if(f.renewable && b->rtime){
1353             t = *b->rtime;
1354             if(t == 0)
1355                 t = MAX_TIME;
1356             if(client->entry.max_renew)
1357                 t = start + min(t - start, *client->entry.max_renew);
1358             if(server->entry.max_renew)
1359                 t = start + min(t - start, *server->entry.max_renew);
1360 #if 0
1361             t = min(t, start + realm->max_renew);
1362 #endif
1363             ALLOC(et.renew_till);
1364             *et.renew_till = t;
1365             et.flags.renewable = 1;
1366         }
1367     }
1368
1369     if (f.request_anonymous)
1370         et.flags.anonymous = 1;
1371     
1372     if(b->addresses){
1373         ALLOC(et.caddr);
1374         copy_HostAddresses(b->addresses, et.caddr);
1375     }
1376     
1377     et.transited.tr_type = DOMAIN_X500_COMPRESS;
1378     krb5_data_zero(&et.transited.contents); 
1379      
1380     copy_EncryptionKey(&et.key, &ek.key);
1381
1382     /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
1383      * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
1384      * incapable of correctly decoding SEQUENCE OF's of zero length.
1385      *
1386      * To fix this, always send at least one no-op last_req
1387      *
1388      * If there's a pw_end or valid_end we will use that,
1389      * otherwise just a dummy lr.
1390      */
1391     ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
1392     ek.last_req.len = 0;
1393     if (client->entry.pw_end
1394         && (config->kdc_warn_pwexpire == 0
1395             || kdc_time + config->kdc_warn_pwexpire <= *client->entry.pw_end)) {
1396         ek.last_req.val[ek.last_req.len].lr_type  = LR_PW_EXPTIME;
1397         ek.last_req.val[ek.last_req.len].lr_value = *client->entry.pw_end;
1398         ++ek.last_req.len;
1399     }
1400     if (client->entry.valid_end) {
1401         ek.last_req.val[ek.last_req.len].lr_type  = LR_ACCT_EXPTIME;
1402         ek.last_req.val[ek.last_req.len].lr_value = *client->entry.valid_end;
1403         ++ek.last_req.len;
1404     }
1405     if (ek.last_req.len == 0) {
1406         ek.last_req.val[ek.last_req.len].lr_type  = LR_NONE;
1407         ek.last_req.val[ek.last_req.len].lr_value = 0;
1408         ++ek.last_req.len;
1409     }
1410     ek.nonce = b->nonce;
1411     if (client->entry.valid_end || client->entry.pw_end) {
1412         ALLOC(ek.key_expiration);
1413         if (client->entry.valid_end) {
1414             if (client->entry.pw_end)
1415                 *ek.key_expiration = min(*client->entry.valid_end, 
1416                                          *client->entry.pw_end);
1417             else
1418                 *ek.key_expiration = *client->entry.valid_end;
1419         } else
1420             *ek.key_expiration = *client->entry.pw_end;
1421     } else
1422         ek.key_expiration = NULL;
1423     ek.flags = et.flags;
1424     ek.authtime = et.authtime;
1425     if (et.starttime) {
1426         ALLOC(ek.starttime);
1427         *ek.starttime = *et.starttime;
1428     }
1429     ek.endtime = et.endtime;
1430     if (et.renew_till) {
1431         ALLOC(ek.renew_till);
1432         *ek.renew_till = *et.renew_till;
1433     }
1434     copy_Realm(&rep.ticket.realm, &ek.srealm);
1435     copy_PrincipalName(&rep.ticket.sname, &ek.sname);
1436     if(et.caddr){
1437         ALLOC(ek.caddr);
1438         copy_HostAddresses(et.caddr, ek.caddr);
1439     }
1440
1441     ALLOC(rep.padata);
1442     rep.padata->len = 0;
1443     rep.padata->val = NULL;
1444
1445     reply_key = &ckey->key;
1446 #if PKINIT
1447     if (pkp) {
1448         ret = _kdc_pk_mk_pa_reply(context, config, pkp, client, 
1449                                   req, req_buffer, 
1450                                   &reply_key, rep.padata);
1451         if (ret)
1452             goto out;
1453     }
1454 #endif
1455
1456     set_salt_padata (rep.padata, ckey->salt);
1457
1458     if (rep.padata->len == 0) {
1459         free(rep.padata);
1460         rep.padata = NULL;
1461     }
1462
1463     /* Add the PAC, via a HDB abstraction */
1464     if (client->authz_data_as_req) {
1465             ret = client->authz_data_as_req(context, client, 
1466                                             req->padata, 
1467                                             et.authtime,
1468                                             &skey->key,
1469                                             &et.key,
1470                                             &et.authorization_data);
1471             if (ret) 
1472                     goto out;
1473     }
1474
1475     log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, 
1476                   et.endtime, et.renew_till);
1477
1478     ret = encode_reply(context, config, 
1479                        &rep, &et, &ek, setype, server->entry.kvno, &skey->key,
1480                        client->entry.kvno, reply_key, &e_text, reply);
1481     free_EncTicketPart(&et);
1482     free_EncKDCRepPart(&ek);
1483  out:
1484     free_AS_REP(&rep);
1485     if(ret){
1486         krb5_mk_error(context,
1487                       ret,
1488                       e_text,
1489                       NULL,
1490                       client_princ,
1491                       server_princ,
1492                       NULL,
1493                       NULL,
1494                       reply);
1495         ret = 0;
1496     }
1497  out2:
1498 #ifdef PKINIT
1499     if (pkp)
1500         _kdc_pk_free_client_param(context, pkp);
1501 #endif
1502     if (client_princ)
1503         krb5_free_principal(context, client_princ);
1504     free(client_name);
1505     if (server_princ)
1506         krb5_free_principal(context, server_princ);
1507     free(server_name);
1508     if(client)
1509         _kdc_free_ent(context, client);
1510     if(server)
1511         _kdc_free_ent(context, server);
1512     return ret;
1513 }
1514
1515
1516 static krb5_error_code
1517 check_tgs_flags(krb5_context context,        
1518                 krb5_kdc_configuration *config,
1519                 KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
1520 {
1521     KDCOptions f = b->kdc_options;
1522         
1523     if(f.validate){
1524         if(!tgt->flags.invalid || tgt->starttime == NULL){
1525             kdc_log(context, config, 0,
1526                     "Bad request to validate ticket");
1527             return KRB5KDC_ERR_BADOPTION;
1528         }
1529         if(*tgt->starttime > kdc_time){
1530             kdc_log(context, config, 0,
1531                     "Early request to validate ticket");
1532             return KRB5KRB_AP_ERR_TKT_NYV;
1533         }
1534         /* XXX  tkt = tgt */
1535         et->flags.invalid = 0;
1536     }else if(tgt->flags.invalid){
1537         kdc_log(context, config, 0, 
1538                 "Ticket-granting ticket has INVALID flag set");
1539         return KRB5KRB_AP_ERR_TKT_INVALID;
1540     }
1541
1542     if(f.forwardable){
1543         if(!tgt->flags.forwardable){
1544             kdc_log(context, config, 0,
1545                     "Bad request for forwardable ticket");
1546             return KRB5KDC_ERR_BADOPTION;
1547         }
1548         et->flags.forwardable = 1;
1549     }
1550     if(f.forwarded){
1551         if(!tgt->flags.forwardable){
1552             kdc_log(context, config, 0,
1553                     "Request to forward non-forwardable ticket");
1554             return KRB5KDC_ERR_BADOPTION;
1555         }
1556         et->flags.forwarded = 1;
1557         et->caddr = b->addresses;
1558     }
1559     if(tgt->flags.forwarded)
1560         et->flags.forwarded = 1;
1561         
1562     if(f.proxiable){
1563         if(!tgt->flags.proxiable){
1564             kdc_log(context, config, 0,
1565                     "Bad request for proxiable ticket");
1566             return KRB5KDC_ERR_BADOPTION;
1567         }
1568         et->flags.proxiable = 1;
1569     }
1570     if(f.proxy){
1571         if(!tgt->flags.proxiable){
1572             kdc_log(context, config, 0,
1573                     "Request to proxy non-proxiable ticket");
1574             return KRB5KDC_ERR_BADOPTION;
1575         }
1576         et->flags.proxy = 1;
1577         et->caddr = b->addresses;
1578     }
1579     if(tgt->flags.proxy)
1580         et->flags.proxy = 1;
1581
1582     if(f.allow_postdate){
1583         if(!tgt->flags.may_postdate){
1584             kdc_log(context, config, 0,
1585                     "Bad request for post-datable ticket");
1586             return KRB5KDC_ERR_BADOPTION;
1587         }
1588         et->flags.may_postdate = 1;
1589     }
1590     if(f.postdated){
1591         if(!tgt->flags.may_postdate){
1592             kdc_log(context, config, 0,
1593                     "Bad request for postdated ticket");
1594             return KRB5KDC_ERR_BADOPTION;
1595         }
1596         if(b->from)
1597             *et->starttime = *b->from;
1598         et->flags.postdated = 1;
1599         et->flags.invalid = 1;
1600     }else if(b->from && *b->from > kdc_time + context->max_skew){
1601         kdc_log(context, config, 0, "Ticket cannot be postdated");
1602         return KRB5KDC_ERR_CANNOT_POSTDATE;
1603     }
1604
1605     if(f.renewable){
1606         if(!tgt->flags.renewable){
1607             kdc_log(context, config, 0,
1608                     "Bad request for renewable ticket");
1609             return KRB5KDC_ERR_BADOPTION;
1610         }
1611         et->flags.renewable = 1;
1612         ALLOC(et->renew_till);
1613         fix_time(&b->rtime);
1614         *et->renew_till = *b->rtime;
1615     }
1616     if(f.renew){
1617         time_t old_life;
1618         if(!tgt->flags.renewable || tgt->renew_till == NULL){
1619             kdc_log(context, config, 0,
1620                     "Request to renew non-renewable ticket");
1621             return KRB5KDC_ERR_BADOPTION;
1622         }
1623         old_life = tgt->endtime;
1624         if(tgt->starttime)
1625             old_life -= *tgt->starttime;
1626         else
1627             old_life -= tgt->authtime;
1628         et->endtime = *et->starttime + old_life;
1629         if (et->renew_till != NULL)
1630             et->endtime = min(*et->renew_till, et->endtime);
1631     }       
1632     
1633     /* checks for excess flags */
1634     if(f.request_anonymous && !config->allow_anonymous){
1635         kdc_log(context, config, 0,
1636                 "Request for anonymous ticket");
1637         return KRB5KDC_ERR_BADOPTION;
1638     }
1639     return 0;
1640 }
1641
1642 static krb5_error_code
1643 fix_transited_encoding(krb5_context context, 
1644                        krb5_kdc_configuration *config,
1645                        krb5_boolean check_policy,
1646                        TransitedEncoding *tr, 
1647                        EncTicketPart *et, 
1648                        const char *client_realm, 
1649                        const char *server_realm, 
1650                        const char *tgt_realm)
1651 {
1652     krb5_error_code ret = 0;
1653     char **realms, **tmp;
1654     int num_realms;
1655     int i;
1656
1657     switch (tr->tr_type) {
1658     case DOMAIN_X500_COMPRESS:
1659         break;
1660     case 0:
1661         /*
1662          * Allow empty content of type 0 because that is was Microsoft
1663          * generates in their TGT.
1664          */
1665         if (tr->contents.length == 0)
1666             break;
1667         kdc_log(context, config, 0,
1668                 "Transited type 0 with non empty content");
1669         return KRB5KDC_ERR_TRTYPE_NOSUPP;
1670     default:
1671         kdc_log(context, config, 0,
1672                 "Unknown transited type: %u", tr->tr_type);
1673         return KRB5KDC_ERR_TRTYPE_NOSUPP;
1674     }
1675
1676     ret = krb5_domain_x500_decode(context, 
1677                                   tr->contents,
1678                                   &realms, 
1679                                   &num_realms,
1680                                   client_realm,
1681                                   server_realm);
1682     if(ret){
1683         krb5_warn(context, ret,
1684                   "Decoding transited encoding");
1685         return ret;
1686     }
1687     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
1688         /* not us, so add the previous realm to transited set */
1689         if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
1690             ret = ERANGE;
1691             goto free_realms;
1692         }
1693         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1694         if(tmp == NULL){
1695             ret = ENOMEM;
1696             goto free_realms;
1697         }
1698         realms = tmp;
1699         realms[num_realms] = strdup(tgt_realm);
1700         if(realms[num_realms] == NULL){
1701             ret = ENOMEM;
1702             goto free_realms;
1703         }
1704         num_realms++;
1705     }
1706     if(num_realms == 0) {
1707         if(strcmp(client_realm, server_realm)) 
1708             kdc_log(context, config, 0,
1709                     "cross-realm %s -> %s", client_realm, server_realm);
1710     } else {
1711         size_t l = 0;
1712         char *rs;
1713         for(i = 0; i < num_realms; i++)
1714             l += strlen(realms[i]) + 2;
1715         rs = malloc(l);
1716         if(rs != NULL) {
1717             *rs = '\0';
1718             for(i = 0; i < num_realms; i++) {
1719                 if(i > 0)
1720                     strlcat(rs, ", ", l);
1721                 strlcat(rs, realms[i], l);
1722             }
1723             kdc_log(context, config, 0,
1724                     "cross-realm %s -> %s via [%s]",
1725                     client_realm, server_realm, rs);
1726             free(rs);
1727         }
1728     }
1729     if(check_policy) {
1730         ret = krb5_check_transited(context, client_realm, 
1731                                    server_realm, 
1732                                    realms, num_realms, NULL);
1733         if(ret) {
1734             krb5_warn(context, ret, "cross-realm %s -> %s", 
1735                       client_realm, server_realm);
1736             goto free_realms;
1737         }
1738         et->flags.transited_policy_checked = 1;
1739     }
1740     et->transited.tr_type = DOMAIN_X500_COMPRESS;
1741     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
1742     if(ret)
1743         krb5_warn(context, ret, "Encoding transited encoding");
1744   free_realms:
1745     for(i = 0; i < num_realms; i++)
1746         free(realms[i]);
1747     free(realms);
1748     return ret;
1749 }
1750
1751
1752 static krb5_error_code
1753 tgs_make_reply(krb5_context context, 
1754                krb5_kdc_configuration *config,
1755                KDC_REQ_BODY *b, 
1756                EncTicketPart *tgt, 
1757                EncTicketPart *adtkt, 
1758                AuthorizationData *auth_data,
1759                krb5_ticket *tgs_ticket,
1760                hdb_entry_ex *server, 
1761                const char *server_name, 
1762                hdb_entry_ex *client, 
1763                krb5_principal client_principal, 
1764                hdb_entry_ex *krbtgt,
1765                EncryptionKey *tgtkey,
1766                krb5_enctype cetype,
1767                const char **e_text,
1768                krb5_data *reply)
1769 {
1770     KDC_REP rep;
1771     EncKDCRepPart ek;
1772     EncTicketPart et;
1773     KDCOptions f = b->kdc_options;
1774     krb5_error_code ret;
1775     krb5_enctype etype;
1776     Key *skey;
1777     EncryptionKey *ekey;
1778     AuthorizationData *new_auth_data = NULL;
1779     
1780     if(adtkt) {
1781         int i;
1782         ekey = &adtkt->key;
1783         for(i = 0; i < b->etype.len; i++)
1784             if (b->etype.val[i] == adtkt->key.keytype)
1785                 break;
1786         if(i == b->etype.len) {
1787             krb5_clear_error_string(context);
1788             return KRB5KDC_ERR_ETYPE_NOSUPP;
1789         }
1790         etype = b->etype.val[i];
1791     }else{
1792         ret = find_keys(context, config, 
1793                         NULL, NULL, server, server_name,
1794                         NULL, NULL, &skey, &etype, 
1795                         b->etype.val, b->etype.len);
1796         if(ret)
1797             return ret;
1798         ekey = &skey->key;
1799     }
1800     
1801     memset(&rep, 0, sizeof(rep));
1802     memset(&et, 0, sizeof(et));
1803     memset(&ek, 0, sizeof(ek));
1804     
1805     rep.pvno = 5;
1806     rep.msg_type = krb_tgs_rep;
1807
1808     et.authtime = tgt->authtime;
1809     fix_time(&b->till);
1810     et.endtime = min(tgt->endtime, *b->till);
1811     ALLOC(et.starttime);
1812     *et.starttime = kdc_time;
1813     
1814     ret = check_tgs_flags(context, config, b, tgt, &et);
1815     if(ret)
1816         goto out;
1817
1818     /* We should check the transited encoding if:
1819        1) the request doesn't ask not to be checked
1820        2) globally enforcing a check
1821        3) principal requires checking
1822        4) we allow non-check per-principal, but principal isn't marked as allowing this
1823        5) we don't globally allow this
1824     */
1825
1826 #define GLOBAL_FORCE_TRANSITED_CHECK            \
1827         (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
1828 #define GLOBAL_ALLOW_PER_PRINCIPAL              \
1829         (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
1830 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK    \
1831         (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
1832
1833 /* these will consult the database in future release */
1834 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
1835 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
1836
1837     ret = fix_transited_encoding(context, config, 
1838                                  !f.disable_transited_check ||
1839                                  GLOBAL_FORCE_TRANSITED_CHECK ||
1840                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
1841                                  !((GLOBAL_ALLOW_PER_PRINCIPAL && 
1842                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
1843                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
1844                                  &tgt->transited, &et,
1845                                  *krb5_princ_realm(context, client_principal),
1846                                  *krb5_princ_realm(context, server->entry.principal),
1847                                  *krb5_princ_realm(context, krbtgt->entry.principal));
1848     if(ret)
1849         goto out;
1850
1851     copy_Realm(krb5_princ_realm(context, server->entry.principal), 
1852                &rep.ticket.realm);
1853     _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
1854     copy_Realm(&tgt->crealm, &rep.crealm);
1855     if (f.request_anonymous)
1856         make_anonymous_principalname (&tgt->cname);
1857     else
1858         copy_PrincipalName(&tgt->cname, &rep.cname);
1859     rep.ticket.tkt_vno = 5;
1860
1861     ek.caddr = et.caddr;
1862     if(et.caddr == NULL)
1863         et.caddr = tgt->caddr;
1864
1865     {
1866         time_t life;
1867         life = et.endtime - *et.starttime;
1868         if(client && client->entry.max_life)
1869             life = min(life, *client->entry.max_life);
1870         if(server->entry.max_life)
1871             life = min(life, *server->entry.max_life);
1872         et.endtime = *et.starttime + life;
1873     }
1874     if(f.renewable_ok && tgt->flags.renewable && 
1875        et.renew_till == NULL && et.endtime < *b->till){
1876         et.flags.renewable = 1;
1877         ALLOC(et.renew_till);
1878         *et.renew_till = *b->till;
1879     }
1880     if(et.renew_till){
1881         time_t renew;
1882         renew = *et.renew_till - et.authtime;
1883         if(client && client->entry.max_renew)
1884             renew = min(renew, *client->entry.max_renew);
1885         if(server->entry.max_renew)
1886             renew = min(renew, *server->entry.max_renew);
1887         *et.renew_till = et.authtime + renew;
1888     }
1889             
1890     if(et.renew_till){
1891         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
1892         *et.starttime = min(*et.starttime, *et.renew_till);
1893         et.endtime = min(et.endtime, *et.renew_till);
1894     }
1895     
1896     *et.starttime = min(*et.starttime, et.endtime);
1897
1898     if(*et.starttime == et.endtime){
1899         ret = KRB5KDC_ERR_NEVER_VALID;
1900         goto out;
1901     }
1902     if(et.renew_till && et.endtime == *et.renew_till){
1903         free(et.renew_till);
1904         et.renew_till = NULL;
1905         et.flags.renewable = 0;
1906     }
1907     
1908     et.flags.pre_authent = tgt->flags.pre_authent;
1909     et.flags.hw_authent  = tgt->flags.hw_authent;
1910     et.flags.anonymous   = tgt->flags.anonymous;
1911     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
1912             
1913     
1914     krb5_generate_random_keyblock(context, etype, &et.key);
1915
1916     if (server->authz_data_tgs_req) {
1917             ret = server->authz_data_tgs_req(context, server,
1918                                              client_principal, 
1919                                              tgs_ticket->ticket.authorization_data,
1920                                              tgs_ticket->ticket.authtime,
1921                                              tgtkey,
1922                                              ekey, 
1923                                              &et.key, 
1924                                              &new_auth_data);
1925             if (ret) {
1926                     new_auth_data = NULL;
1927             }
1928     }
1929
1930     /* XXX Check enc-authorization-data */
1931     et.authorization_data = new_auth_data;
1932
1933     et.crealm = tgt->crealm;
1934     et.cname = tgt->cname;
1935             
1936     ek.key = et.key;
1937     /* MIT must have at least one last_req */
1938     ek.last_req.len = 1;
1939     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1940     ek.nonce = b->nonce;
1941     ek.flags = et.flags;
1942     ek.authtime = et.authtime;
1943     ek.starttime = et.starttime;
1944     ek.endtime = et.endtime;
1945     ek.renew_till = et.renew_till;
1946     ek.srealm = rep.ticket.realm;
1947     ek.sname = rep.ticket.sname;
1948     
1949     log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, 
1950                   et.endtime, et.renew_till);
1951
1952     /* It is somewhat unclear where the etype in the following
1953        encryption should come from. What we have is a session
1954        key in the passed tgt, and a list of preferred etypes
1955        *for the new ticket*. Should we pick the best possible
1956        etype, given the keytype in the tgt, or should we look
1957        at the etype list here as well?  What if the tgt
1958        session key is DES3 and we want a ticket with a (say)
1959        CAST session key. Should the DES3 etype be added to the
1960        etype list, even if we don't want a session key with
1961        DES3? */
1962     ret = encode_reply(context, config, 
1963                        &rep, &et, &ek, etype, adtkt ? 0 : server->entry.kvno, 
1964                        ekey, 0, &tgt->key, e_text, reply);
1965   out:
1966     free_TGS_REP(&rep);
1967     free_TransitedEncoding(&et.transited);
1968     if(et.starttime)
1969         free(et.starttime);
1970     if(et.renew_till)
1971         free(et.renew_till);
1972     free_LastReq(&ek.last_req);
1973     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1974     free_EncryptionKey(&et.key);
1975     return ret;
1976 }
1977
1978 static krb5_error_code
1979 tgs_check_authenticator(krb5_context context, 
1980                         krb5_kdc_configuration *config,
1981                         krb5_auth_context ac,
1982                         KDC_REQ_BODY *b, 
1983                         const char **e_text,
1984                         krb5_keyblock *key)
1985 {
1986     krb5_authenticator auth;
1987     size_t len;
1988     unsigned char *buf;
1989     size_t buf_size;
1990     krb5_error_code ret;
1991     krb5_crypto crypto;
1992     
1993     krb5_auth_con_getauthenticator(context, ac, &auth);
1994     if(auth->cksum == NULL){
1995         kdc_log(context, config, 0, "No authenticator in request");
1996         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1997         goto out;
1998     }
1999     /*
2000      * according to RFC1510 it doesn't need to be keyed,
2001      * but according to the latest draft it needs to.
2002      */
2003     if (
2004 #if 0
2005 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
2006         ||
2007 #endif
2008  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
2009         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 
2010                 auth->cksum->cksumtype);
2011         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
2012         goto out;
2013     }
2014                 
2015     /* XXX should not re-encode this */
2016     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
2017     if(ret){
2018         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", 
2019                 krb5_get_err_text(context, ret));
2020         goto out;
2021     }
2022     if(buf_size != len) {
2023         free(buf);
2024         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
2025         *e_text = "KDC internal error";
2026         ret = KRB5KRB_ERR_GENERIC;
2027         goto out;
2028     }
2029     ret = krb5_crypto_init(context, key, 0, &crypto);
2030     if (ret) {
2031         free(buf);
2032         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
2033                 krb5_get_err_text(context, ret));
2034         goto out;
2035     }
2036     ret = krb5_verify_checksum(context,
2037                                crypto,
2038                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
2039                                buf, 
2040                                len,
2041                                auth->cksum);
2042     free(buf);
2043     krb5_crypto_destroy(context, crypto);
2044     if(ret){
2045         kdc_log(context, config, 0,
2046                 "Failed to verify authenticator checksum: %s", 
2047                 krb5_get_err_text(context, ret));
2048     }
2049 out:
2050     free_Authenticator(auth);
2051     free(auth);
2052     return ret;
2053 }
2054
2055 /*
2056  * return the realm of a krbtgt-ticket or NULL
2057  */
2058
2059 static Realm 
2060 get_krbtgt_realm(const PrincipalName *p)
2061 {
2062     if(p->name_string.len == 2
2063        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
2064         return p->name_string.val[1];
2065     else
2066         return NULL;
2067 }
2068
2069 static const char *
2070 find_rpath(krb5_context context, Realm crealm, Realm srealm)
2071 {
2072     const char *new_realm = krb5_config_get_string(context,
2073                                                    NULL,
2074                                                    "capaths", 
2075                                                    crealm,
2076                                                    srealm,
2077                                                    NULL);
2078     return new_realm;
2079 }
2080             
2081
2082 static krb5_boolean
2083 need_referral(krb5_context context, krb5_principal server, krb5_realm **realms)
2084 {
2085     if(server->name.name_type != KRB5_NT_SRV_INST ||
2086        server->name.name_string.len != 2)
2087         return FALSE;
2088  
2089     return _krb5_get_host_realm_int(context, server->name.name_string.val[1],
2090                                     FALSE, realms) == 0;
2091 }
2092
2093 static krb5_error_code
2094 tgs_rep2(krb5_context context, 
2095          krb5_kdc_configuration *config,
2096          KDC_REQ_BODY *b,
2097          PA_DATA *tgs_req,
2098          krb5_data *reply,
2099          const char *from,
2100          const struct sockaddr *from_addr,
2101          time_t **csec,
2102          int **cusec)
2103 {
2104     krb5_ap_req ap_req;
2105     krb5_error_code ret;
2106     krb5_principal princ;
2107     krb5_auth_context ac = NULL;
2108     krb5_ticket *ticket = NULL;
2109     krb5_flags ap_req_options;
2110     krb5_flags verify_ap_req_flags;
2111     const char *e_text = NULL;
2112     krb5_crypto crypto;
2113
2114     hdb_entry_ex *krbtgt = NULL;
2115     EncTicketPart *tgt;
2116     Key *tkey;
2117     krb5_enctype cetype;
2118     krb5_principal cp = NULL;
2119     krb5_principal sp = NULL;
2120     AuthorizationData *auth_data = NULL;
2121
2122     *csec  = NULL;
2123     *cusec = NULL;
2124
2125     memset(&ap_req, 0, sizeof(ap_req));
2126     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
2127     if(ret){
2128         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", 
2129                 krb5_get_err_text(context, ret));
2130         goto out2;
2131     }
2132     
2133     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
2134         /* XXX check for ticket.sname == req.sname */
2135         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
2136         ret = KRB5KDC_ERR_POLICY; /* ? */
2137         goto out2;
2138     }
2139     
2140     _krb5_principalname2krb5_principal(context, &princ,
2141                                        ap_req.ticket.sname,
2142                                        ap_req.ticket.realm);
2143     
2144     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, &krbtgt);
2145
2146     if(ret) {
2147         char *p;
2148         ret = krb5_unparse_name(context, princ, &p);
2149         if (ret != 0)
2150             p = "<unparse_name failed>";
2151         krb5_free_principal(context, princ);
2152         kdc_log(context, config, 0,
2153                 "Ticket-granting ticket not found in database: %s: %s",
2154                 p, krb5_get_err_text(context, ret));
2155         if (ret == 0)
2156             free(p);
2157         ret = KRB5KRB_AP_ERR_NOT_US;
2158         goto out2;
2159     }
2160     
2161     if(ap_req.ticket.enc_part.kvno && 
2162        *ap_req.ticket.enc_part.kvno != krbtgt->entry.kvno){
2163         char *p;
2164
2165         ret = krb5_unparse_name (context, princ, &p);
2166         krb5_free_principal(context, princ);
2167         if (ret != 0)
2168             p = "<unparse_name failed>";
2169         kdc_log(context, config, 0,
2170                 "Ticket kvno = %d, DB kvno = %d (%s)", 
2171                 *ap_req.ticket.enc_part.kvno,
2172                 krbtgt->entry.kvno,
2173                 p);
2174         if (ret == 0)
2175             free (p);
2176         ret = KRB5KRB_AP_ERR_BADKEYVER;
2177         goto out2;
2178     }
2179
2180     ret = hdb_enctype2key(context, &krbtgt->entry, 
2181                           ap_req.ticket.enc_part.etype, &tkey);
2182     if(ret){
2183         char *str, *p;
2184         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
2185         krb5_unparse_name(context, princ, &p);
2186         kdc_log(context, config, 0,
2187                 "No server key with enctype %s found for %s", str, p);
2188         free(str);
2189         free(p);
2190         ret = KRB5KRB_AP_ERR_BADKEYVER;
2191         goto out2;
2192     }
2193     
2194     if (b->kdc_options.validate)
2195         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
2196     else
2197         verify_ap_req_flags = 0;
2198
2199     ret = krb5_verify_ap_req2(context,
2200                               &ac,
2201                               &ap_req,
2202                               princ,
2203                               &tkey->key,
2204                               verify_ap_req_flags,
2205                               &ap_req_options,
2206                               &ticket,
2207                               KRB5_KU_TGS_REQ_AUTH);
2208                              
2209     krb5_free_principal(context, princ);
2210     if(ret) {
2211         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", 
2212                 krb5_get_err_text(context, ret));
2213         goto out2;
2214     }
2215
2216     {
2217         krb5_authenticator auth;
2218
2219         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
2220         if (ret == 0) {
2221             *csec   = malloc(sizeof(**csec));
2222             if (*csec == NULL) {
2223                 krb5_free_authenticator(context, &auth);
2224                 kdc_log(context, config, 0, "malloc failed");
2225                 goto out2;
2226             }
2227             **csec  = auth->ctime;
2228             *cusec  = malloc(sizeof(**cusec));
2229             if (*cusec == NULL) {
2230                 krb5_free_authenticator(context, &auth);
2231                 kdc_log(context, config, 0, "malloc failed");
2232                 goto out2;
2233             }
2234             **csec  = auth->cusec;
2235             krb5_free_authenticator(context, &auth);
2236         }
2237     }
2238
2239     cetype = ap_req.authenticator.etype;
2240
2241     tgt = &ticket->ticket;
2242
2243     ret = tgs_check_authenticator(context, config, 
2244                                   ac, b, &e_text, &tgt->key);
2245     if (ret) {
2246         krb5_auth_con_free(context, ac);
2247         goto out2;
2248     }
2249
2250     if (b->enc_authorization_data) {
2251         krb5_keyblock *subkey;
2252         krb5_data ad;
2253         ret = krb5_auth_con_getremotesubkey(context,
2254                                             ac,
2255                                             &subkey);
2256         if(ret){
2257             krb5_auth_con_free(context, ac);
2258             kdc_log(context, config, 0, "Failed to get remote subkey: %s", 
2259                     krb5_get_err_text(context, ret));
2260             goto out2;
2261         }
2262         if(subkey == NULL){
2263             ret = krb5_auth_con_getkey(context, ac, &subkey);
2264             if(ret) {
2265                 krb5_auth_con_free(context, ac);
2266                 kdc_log(context, config, 0, "Failed to get session key: %s", 
2267                         krb5_get_err_text(context, ret));
2268                 goto out2;
2269             }
2270         }
2271         if(subkey == NULL){
2272             krb5_auth_con_free(context, ac);
2273             kdc_log(context, config, 0,
2274                     "Failed to get key for enc-authorization-data");
2275             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
2276             goto out2;
2277         }
2278         ret = krb5_crypto_init(context, subkey, 0, &crypto);
2279         if (ret) {
2280             krb5_auth_con_free(context, ac);
2281             kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
2282                     krb5_get_err_text(context, ret));
2283             goto out2;
2284         }
2285         ret = krb5_decrypt_EncryptedData (context,
2286                                           crypto,
2287                                           KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
2288                                           b->enc_authorization_data,
2289                                           &ad);
2290         krb5_crypto_destroy(context, crypto);
2291         if(ret){
2292             krb5_auth_con_free(context, ac);
2293             kdc_log(context, config, 0, "Failed to decrypt enc-authorization-data");
2294             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
2295             goto out2;
2296         }
2297         krb5_free_keyblock(context, subkey);
2298         ALLOC(auth_data);
2299         ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
2300         if(ret){
2301             krb5_auth_con_free(context, ac);
2302             free(auth_data);
2303             auth_data = NULL;
2304             kdc_log(context, config, 0, "Failed to decode authorization data");
2305             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
2306             goto out2;
2307         }
2308     }
2309
2310     krb5_auth_con_free(context, ac);
2311
2312     {
2313         PrincipalName *s;
2314         Realm r;
2315         char *spn = NULL, *cpn = NULL;
2316         hdb_entry_ex *server = NULL, *client = NULL;
2317         int nloop = 0;
2318         EncTicketPart adtkt;
2319         char opt_str[128];
2320
2321         s = b->sname;
2322         r = b->realm;
2323         if(b->kdc_options.enc_tkt_in_skey){
2324             Ticket *t;
2325             hdb_entry_ex *uu;
2326             krb5_principal p;
2327             Key *uukey;
2328             
2329             if(b->additional_tickets == NULL || 
2330                b->additional_tickets->len == 0){
2331                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
2332                 kdc_log(context, config, 0,
2333                         "No second ticket present in request");
2334                 goto out;
2335             }
2336             t = &b->additional_tickets->val[0];
2337             if(!get_krbtgt_realm(&t->sname)){
2338                 kdc_log(context, config, 0,
2339                         "Additional ticket is not a ticket-granting ticket");
2340                 ret = KRB5KDC_ERR_POLICY;
2341                 goto out2;
2342             }
2343             _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
2344             ret = _kdc_db_fetch(context, config, p, 
2345                                 HDB_F_GET_CLIENT|HDB_F_GET_SERVER, &uu);
2346             krb5_free_principal(context, p);
2347             if(ret){
2348                 if (ret == HDB_ERR_NOENTRY)
2349                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
2350                 goto out;
2351             }
2352             ret = hdb_enctype2key(context, &uu->entry, 
2353                                   t->enc_part.etype, &uukey);
2354             if(ret){
2355                 _kdc_free_ent(context, uu);
2356                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2357                 goto out;
2358             }
2359             ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
2360             _kdc_free_ent(context, uu);
2361             if(ret)
2362                 goto out;
2363             s = &adtkt.cname;
2364             r = adtkt.crealm;
2365         }
2366
2367         _krb5_principalname2krb5_principal(context, &sp, *s, r);
2368         ret = krb5_unparse_name(context, sp, &spn);     
2369         if (ret)
2370             goto out;
2371         _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
2372         ret = krb5_unparse_name(context, cp, &cpn);
2373         if (ret)
2374             goto out;
2375         unparse_flags (KDCOptions2int(b->kdc_options),
2376                        asn1_KDCOptions_units(),
2377                        opt_str, sizeof(opt_str));
2378         if(*opt_str)
2379             kdc_log(context, config, 0,
2380                     "TGS-REQ %s from %s for %s [%s]", 
2381                     cpn, from, spn, opt_str);
2382         else
2383             kdc_log(context, config, 0,
2384                     "TGS-REQ %s from %s for %s", cpn, from, spn);
2385     server_lookup:
2386         ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, &server);
2387
2388         if(ret){
2389             const char *new_rlm;
2390             Realm req_rlm;
2391             krb5_realm *realms;
2392
2393             if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
2394                 if(nloop++ < 2) {
2395                     new_rlm = find_rpath(context, tgt->crealm, req_rlm);
2396                     if(new_rlm) {
2397                         kdc_log(context, config, 5, "krbtgt for realm %s not found, trying %s", 
2398                                 req_rlm, new_rlm);
2399                         krb5_free_principal(context, sp);
2400                         free(spn);
2401                         krb5_make_principal(context, &sp, r, 
2402                                             KRB5_TGS_NAME, new_rlm, NULL);
2403                         ret = krb5_unparse_name(context, sp, &spn);     
2404                         if (ret)
2405                             goto out;
2406                         goto server_lookup;
2407                     }
2408                 }
2409             } else if(need_referral(context, sp, &realms)) {
2410                 if (strcmp(realms[0], sp->realm) != 0) {
2411                     kdc_log(context, config, 5,
2412                             "Returning a referral to realm %s for "
2413                             "server %s that was not found",
2414                             realms[0], spn);
2415                     krb5_free_principal(context, sp);
2416                     free(spn);
2417                     krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
2418                                         realms[0], NULL);
2419                     ret = krb5_unparse_name(context, sp, &spn);
2420                     if (ret)
2421                         goto out;
2422                     krb5_free_host_realm(context, realms);
2423                     goto server_lookup;
2424                 }
2425                 krb5_free_host_realm(context, realms);
2426             }
2427             kdc_log(context, config, 0,
2428                     "Server not found in database: %s: %s", spn,
2429                     krb5_get_err_text(context, ret));
2430             if (ret == HDB_ERR_NOENTRY)
2431                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
2432             goto out;
2433         }
2434
2435         ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, &client);
2436         if(ret)
2437             kdc_log(context, config, 1, "Client not found in database: %s: %s",
2438                     cpn, krb5_get_err_text(context, ret));
2439
2440         /*
2441          * If the client belongs to the same realm as our krbtgt, it
2442          * should exist in the local database.
2443          *
2444          * If its not the same, check the "direction" on the krbtgt,
2445          * so its not a backward uni-directional trust.
2446          */
2447
2448         if(strcmp(krb5_principal_get_realm(context, sp),
2449                   krb5_principal_get_comp_string(context, 
2450                                                  krbtgt->entry.principal, 1)) == 0) {
2451             if(ret) {
2452                 if (ret == HDB_ERR_NOENTRY)
2453                     ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2454                 goto out;
2455             }
2456         } else {
2457             char *tpn;
2458             ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
2459             kdc_log(context, config, 0,
2460                     "Request with wrong krbtgt: %s",
2461                     (ret == 0) ? tpn : "<unknown>");
2462             if(ret == 0)
2463                 free(tpn);
2464             ret = KRB5KRB_AP_ERR_NOT_US;
2465             goto out;
2466             
2467         }
2468
2469         ret = _kdc_check_flags(context, config, 
2470                                client, cpn,
2471                                server, spn,
2472                                FALSE);
2473         if(ret)
2474             goto out;
2475
2476         if((b->kdc_options.validate || b->kdc_options.renew) && 
2477            !krb5_principal_compare(context, 
2478                                    krbtgt->entry.principal,
2479                                    server->entry.principal)){
2480             kdc_log(context, config, 0, "Inconsistent request.");
2481             ret = KRB5KDC_ERR_SERVER_NOMATCH;
2482             goto out;
2483         }
2484
2485         /* check for valid set of addresses */
2486         if(!check_addresses(context, config, tgt->caddr, from_addr)) {
2487             ret = KRB5KRB_AP_ERR_BADADDR;
2488             kdc_log(context, config, 0, "Request from wrong address");
2489             goto out;
2490         }
2491         
2492         ret = tgs_make_reply(context,
2493                              config, 
2494                              b, 
2495                              tgt, 
2496                              b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
2497                              auth_data,
2498                              ticket,
2499                              server, 
2500                              spn,
2501                              client, 
2502                              cp, 
2503                              krbtgt, 
2504                              &tkey->key,
2505                              cetype, 
2506                              &e_text,
2507                              reply);
2508         
2509     out:
2510         free(spn);
2511         free(cpn);
2512             
2513         if(server)
2514             _kdc_free_ent(context, server);
2515         if(client)
2516             _kdc_free_ent(context, client);
2517     }
2518  out2:
2519     if(ret) {
2520         krb5_mk_error(context,
2521                       ret,
2522                       e_text,
2523                       NULL,
2524                       cp,
2525                       sp,
2526                       NULL,
2527                       NULL,
2528                       reply);
2529         free(*csec);
2530         free(*cusec);
2531         *csec  = NULL;
2532         *cusec = NULL;
2533     }
2534     krb5_free_principal(context, cp);
2535     krb5_free_principal(context, sp);
2536     if (ticket)
2537         krb5_free_ticket(context, ticket);
2538     free_AP_REQ(&ap_req);
2539     if(auth_data){
2540         free_AuthorizationData(auth_data);
2541         free(auth_data);
2542     }
2543
2544     if(krbtgt)
2545         _kdc_free_ent(context, krbtgt);
2546
2547     return ret;
2548 }
2549
2550
2551 krb5_error_code
2552 _kdc_tgs_rep(krb5_context context, 
2553              krb5_kdc_configuration *config,
2554              KDC_REQ *req, 
2555              krb5_data *data,
2556              const char *from,
2557              struct sockaddr *from_addr)
2558 {
2559     krb5_error_code ret;
2560     int i = 0;
2561     PA_DATA *tgs_req = NULL;
2562     time_t *csec = NULL;
2563     int *cusec = NULL;
2564
2565     if(req->padata == NULL){
2566         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2567         kdc_log(context, config, 0,
2568                 "TGS-REQ from %s without PA-DATA", from);
2569         goto out;
2570     }
2571     
2572     tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2573
2574     if(tgs_req == NULL){
2575         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2576         
2577         kdc_log(context, config, 0, 
2578                 "TGS-REQ from %s without PA-TGS-REQ", from);
2579         goto out;
2580     }
2581     ret = tgs_rep2(context, config, 
2582                    &req->req_body, tgs_req, data, from, from_addr,
2583                    &csec, &cusec);
2584 out:
2585     if(ret && data->data == NULL){
2586         krb5_mk_error(context,
2587                       ret,
2588                       NULL,
2589                       NULL,
2590                       NULL,
2591                       NULL,
2592                       csec,
2593                       cusec,
2594                       data);
2595     }
2596     free(csec);
2597     free(cusec);
2598     return 0;
2599 }