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