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