Merge from vendor branch NTPD:
[dragonfly.git] / crypto / heimdal-0.6.3 / kdc / kerberos5.c
1 /*
2  * Copyright (c) 1997-2003 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.145.2.4 2004/08/13 19:28:26 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 void
51 set_salt_padata (METHOD_DATA **m, Salt *salt)
52 {
53     if (salt) {
54         ALLOC(*m);
55         (*m)->len = 1;
56         ALLOC((*m)->val);
57         (*m)->val->padata_type = salt->type;
58         copy_octet_string(&salt->salt,
59                           &(*m)->val->padata_value);
60     }
61 }
62
63 static PA_DATA*
64 find_padata(KDC_REQ *req, int *start, int type)
65 {
66     while(*start < req->padata->len){
67         (*start)++;
68         if(req->padata->val[*start - 1].padata_type == type)
69             return &req->padata->val[*start - 1];
70     }
71     return NULL;
72 }
73
74 /*
75  * return the first appropriate key of `princ' in `ret_key'.  Look for
76  * all the etypes in (`etypes', `len'), stopping as soon as we find
77  * one, but preferring one that has default salt
78  */
79
80 static krb5_error_code
81 find_etype(hdb_entry *princ, krb5_enctype *etypes, unsigned len, 
82            Key **ret_key, krb5_enctype *ret_etype)
83 {
84     int i;
85     krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP;
86
87     for(i = 0; ret != 0 && i < len ; i++) {
88         Key *key = NULL;
89
90         while (hdb_next_enctype2key(context, princ, etypes[i], &key) == 0) {
91             if (key->key.keyvalue.length == 0) {
92                 ret = KRB5KDC_ERR_NULL_KEY;
93                 continue;
94             }
95             *ret_key   = key;
96             *ret_etype = etypes[i];
97             ret = 0;
98             if (key->salt == NULL)
99                 return ret;
100         }
101     }
102     return ret;
103 }
104
105 static krb5_error_code
106 find_keys(hdb_entry *client,
107           hdb_entry *server, 
108           Key **ckey,
109           krb5_enctype *cetype,
110           Key **skey,
111           krb5_enctype *setype, 
112           krb5_enctype *etypes,
113           unsigned num_etypes)
114 {
115     krb5_error_code ret;
116
117     if(client){
118         /* find client key */
119         ret = find_etype(client, etypes, num_etypes, ckey, cetype);
120         if (ret) {
121             kdc_log(0, "Client has no support for etypes");
122             return ret;
123         }
124     }
125
126     if(server){
127         /* find server key */
128         ret = find_etype(server, etypes, num_etypes, skey, setype);
129         if (ret) {
130             kdc_log(0, "Server has no support for etypes");
131             return ret;
132         }
133     }
134     return 0;
135 }
136
137 static krb5_error_code
138 make_anonymous_principalname (PrincipalName *pn)
139 {
140     pn->name_type = KRB5_NT_PRINCIPAL;
141     pn->name_string.len = 1;
142     pn->name_string.val = malloc(sizeof(*pn->name_string.val));
143     if (pn->name_string.val == NULL)
144         return ENOMEM;
145     pn->name_string.val[0] = strdup("anonymous");
146     if (pn->name_string.val[0] == NULL) {
147         free(pn->name_string.val);
148         pn->name_string.val = NULL;
149         return ENOMEM;
150     }
151     return 0;
152 }
153
154 static krb5_error_code
155 encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, 
156              krb5_enctype etype, 
157              int skvno, EncryptionKey *skey,
158              int ckvno, EncryptionKey *ckey,
159              const char **e_text,
160              krb5_data *reply)
161 {
162     unsigned char *buf;
163     size_t buf_size;
164     size_t len;
165     krb5_error_code ret;
166     krb5_crypto crypto;
167
168     ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret);
169     if(ret) {
170         kdc_log(0, "Failed to encode ticket: %s", 
171                 krb5_get_err_text(context, ret));
172         return ret;
173     }
174     if(buf_size != len) {
175         free(buf);
176         kdc_log(0, "Internal error in ASN.1 encoder");
177         *e_text = "KDC internal error";
178         return KRB5KRB_ERR_GENERIC;
179     }
180
181     ret = krb5_crypto_init(context, skey, etype, &crypto);
182     if (ret) {
183         free(buf);
184         kdc_log(0, "krb5_crypto_init failed: %s",
185                 krb5_get_err_text(context, ret));
186         return ret;
187     }
188
189     ret = krb5_encrypt_EncryptedData(context, 
190                                      crypto,
191                                      KRB5_KU_TICKET,
192                                      buf,
193                                      len,
194                                      skvno,
195                                      &rep->ticket.enc_part);
196     free(buf);
197     krb5_crypto_destroy(context, crypto);
198     if(ret) {
199         kdc_log(0, "Failed to encrypt data: %s",
200                 krb5_get_err_text(context, ret));
201         return ret;
202     }
203     
204     if(rep->msg_type == krb_as_rep && !encode_as_rep_as_tgs_rep)
205         ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret);
206     else
207         ASN1_MALLOC_ENCODE(EncTGSRepPart, buf, buf_size, ek, &len, ret);
208     if(ret) {
209         kdc_log(0, "Failed to encode KDC-REP: %s", 
210                 krb5_get_err_text(context, ret));
211         return ret;
212     }
213     if(buf_size != len) {
214         free(buf);
215         kdc_log(0, "Internal error in ASN.1 encoder");
216         *e_text = "KDC internal error";
217         return KRB5KRB_ERR_GENERIC;
218     }
219     ret = krb5_crypto_init(context, ckey, 0, &crypto);
220     if (ret) {
221         free(buf);
222         kdc_log(0, "krb5_crypto_init failed: %s",
223                 krb5_get_err_text(context, ret));
224         return ret;
225     }
226     if(rep->msg_type == krb_as_rep) {
227         krb5_encrypt_EncryptedData(context,
228                                    crypto,
229                                    KRB5_KU_AS_REP_ENC_PART,
230                                    buf,
231                                    len,
232                                    ckvno,
233                                    &rep->enc_part);
234         free(buf);
235         ASN1_MALLOC_ENCODE(AS_REP, buf, buf_size, rep, &len, ret);
236     } else {
237         krb5_encrypt_EncryptedData(context,
238                                    crypto,
239                                    KRB5_KU_TGS_REP_ENC_PART_SESSION,
240                                    buf,
241                                    len,
242                                    ckvno,
243                                    &rep->enc_part);
244         free(buf);
245         ASN1_MALLOC_ENCODE(TGS_REP, buf, buf_size, rep, &len, ret);
246     }
247     krb5_crypto_destroy(context, crypto);
248     if(ret) {
249         kdc_log(0, "Failed to encode KDC-REP: %s", 
250                 krb5_get_err_text(context, ret));
251         return ret;
252     }
253     if(buf_size != len) {
254         free(buf);
255         kdc_log(0, "Internal error in ASN.1 encoder");
256         *e_text = "KDC internal error";
257         return KRB5KRB_ERR_GENERIC;
258     }
259     reply->data = buf;
260     reply->length = buf_size;
261     return 0;
262 }
263
264 static int
265 realloc_method_data(METHOD_DATA *md)
266 {
267     PA_DATA *pa;
268     pa = realloc(md->val, (md->len + 1) * sizeof(*md->val));
269     if(pa == NULL)
270         return ENOMEM;
271     md->val = pa;
272     md->len++;
273     return 0;
274 }
275
276 static krb5_error_code
277 make_etype_info_entry(ETYPE_INFO_ENTRY *ent, Key *key)
278 {
279     ent->etype = key->key.keytype;
280     if(key->salt){
281         ALLOC(ent->salttype);
282 #if 0
283         if(key->salt->type == hdb_pw_salt)
284             *ent->salttype = 0; /* or 1? or NULL? */
285         else if(key->salt->type == hdb_afs3_salt)
286             *ent->salttype = 2;
287         else {
288             kdc_log(0, "unknown salt-type: %d", 
289                     key->salt->type);
290             return KRB5KRB_ERR_GENERIC;
291         }
292         /* according to `the specs', we can't send a salt if
293            we have AFS3 salted key, but that requires that you
294            *know* what cell you are using (e.g by assuming
295            that the cell is the same as the realm in lower
296            case) */
297 #else
298         *ent->salttype = key->salt->type;
299 #endif
300         krb5_copy_data(context, &key->salt->salt,
301                        &ent->salt);
302     } else {
303         /* we return no salt type at all, as that should indicate
304          * the default salt type and make everybody happy.  some
305          * systems (like w2k) dislike being told the salt type
306          * here. */
307
308         ent->salttype = NULL;
309         ent->salt = NULL;
310     }
311     return 0;
312 }
313
314 static krb5_error_code
315 get_pa_etype_info(METHOD_DATA *md, hdb_entry *client, 
316                   ENCTYPE *etypes, unsigned int etypes_len)
317 {
318     krb5_error_code ret = 0;
319     int i, j;
320     unsigned int n = 0;
321     ETYPE_INFO pa;
322     unsigned char *buf;
323     size_t len;
324     
325
326     pa.len = client->keys.len;
327     if(pa.len > UINT_MAX/sizeof(*pa.val))
328         return ERANGE;
329     pa.val = malloc(pa.len * sizeof(*pa.val));
330     if(pa.val == NULL)
331         return ENOMEM;
332
333     for(j = 0; j < etypes_len; j++) {
334         for (i = 0; i < n; i++)
335             if (pa.val[i].etype == etypes[j])
336                 goto skip1;
337         for(i = 0; i < client->keys.len; i++) {
338             if(client->keys.val[i].key.keytype == etypes[j])
339                 if((ret = make_etype_info_entry(&pa.val[n++], 
340                                                 &client->keys.val[i])) != 0) {
341                     free_ETYPE_INFO(&pa);
342                     return ret;
343                 }
344         }
345     skip1:;
346     }
347     for(i = 0; i < client->keys.len; i++) {
348         for(j = 0; j < etypes_len; j++) {
349             if(client->keys.val[i].key.keytype == etypes[j])
350                 goto skip2;
351         }
352         if((ret = make_etype_info_entry(&pa.val[n++], 
353                                         &client->keys.val[i])) != 0) {
354             free_ETYPE_INFO(&pa);
355             return ret;
356         }
357       skip2:;
358     }
359     
360     if(n != pa.len) {
361         char *name;
362         krb5_unparse_name(context, client->principal, &name);
363         kdc_log(0, "internal error in get_pa_etype_info(%s): %d != %d", 
364                 name, n, pa.len);
365         free(name);
366         pa.len = n;
367     }
368
369     ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
370     free_ETYPE_INFO(&pa);
371     if(ret)
372         return ret;
373     ret = realloc_method_data(md);
374     if(ret) {
375         free(buf);
376         return ret;
377     }
378     md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO;
379     md->val[md->len - 1].padata_value.length = len;
380     md->val[md->len - 1].padata_value.data = buf;
381     return 0;
382 }
383
384 /*
385  * verify the flags on `client' and `server', returning 0
386  * if they are OK and generating an error messages and returning
387  * and error code otherwise.
388  */
389
390 krb5_error_code
391 check_flags(hdb_entry *client, const char *client_name,
392             hdb_entry *server, const char *server_name,
393             krb5_boolean is_as_req)
394 {
395     if(client != NULL) {
396         /* check client */
397         if (client->flags.invalid) {
398             kdc_log(0, "Client (%s) has invalid bit set", client_name);
399             return KRB5KDC_ERR_POLICY;
400         }
401         
402         if(!client->flags.client){
403             kdc_log(0, "Principal may not act as client -- %s", 
404                     client_name);
405             return KRB5KDC_ERR_POLICY;
406         }
407         
408         if (client->valid_start && *client->valid_start > kdc_time) {
409             kdc_log(0, "Client not yet valid -- %s", client_name);
410             return KRB5KDC_ERR_CLIENT_NOTYET;
411         }
412         
413         if (client->valid_end && *client->valid_end < kdc_time) {
414             kdc_log(0, "Client expired -- %s", client_name);
415             return KRB5KDC_ERR_NAME_EXP;
416         }
417         
418         if (client->pw_end && *client->pw_end < kdc_time
419             && !server->flags.change_pw) {
420             kdc_log(0, "Client's key has expired -- %s", client_name);
421             return KRB5KDC_ERR_KEY_EXPIRED;
422         }
423     }
424
425     /* check server */
426     
427     if (server != NULL) {
428         if (server->flags.invalid) {
429             kdc_log(0, "Server has invalid flag set -- %s", server_name);
430             return KRB5KDC_ERR_POLICY;
431         }
432
433         if(!server->flags.server){
434             kdc_log(0, "Principal may not act as server -- %s", 
435                     server_name);
436             return KRB5KDC_ERR_POLICY;
437         }
438
439         if(!is_as_req && server->flags.initial) {
440             kdc_log(0, "AS-REQ is required for server -- %s", server_name);
441             return KRB5KDC_ERR_POLICY;
442         }
443
444         if (server->valid_start && *server->valid_start > kdc_time) {
445             kdc_log(0, "Server not yet valid -- %s", server_name);
446             return KRB5KDC_ERR_SERVICE_NOTYET;
447         }
448
449         if (server->valid_end && *server->valid_end < kdc_time) {
450             kdc_log(0, "Server expired -- %s", server_name);
451             return KRB5KDC_ERR_SERVICE_EXP;
452         }
453
454         if (server->pw_end && *server->pw_end < kdc_time) {
455             kdc_log(0, "Server's key has expired -- %s", server_name);
456             return KRB5KDC_ERR_KEY_EXPIRED;
457         }
458     }
459     return 0;
460 }
461
462 /*
463  * Return TRUE if `from' is part of `addresses' taking into consideration
464  * the configuration variables that tells us how strict we should be about
465  * these checks
466  */
467
468 static krb5_boolean
469 check_addresses(HostAddresses *addresses, const struct sockaddr *from)
470 {
471     krb5_error_code ret;
472     krb5_address addr;
473     krb5_boolean result;
474     
475     if(check_ticket_addresses == 0)
476         return TRUE;
477
478     if(addresses == NULL)
479         return allow_null_ticket_addresses;
480     
481     ret = krb5_sockaddr2address (context, from, &addr);
482     if(ret)
483         return FALSE;
484
485     result = krb5_address_search(context, &addr, addresses);
486     krb5_free_address (context, &addr);
487     return result;
488 }
489
490 krb5_error_code
491 as_rep(KDC_REQ *req, 
492        krb5_data *reply,
493        const char *from,
494        struct sockaddr *from_addr)
495 {
496     KDC_REQ_BODY *b = &req->req_body;
497     AS_REP rep;
498     KDCOptions f = b->kdc_options;
499     hdb_entry *client = NULL, *server = NULL;
500     krb5_enctype cetype, setype;
501     EncTicketPart et;
502     EncKDCRepPart ek;
503     krb5_principal client_princ = NULL, server_princ = NULL;
504     char *client_name = NULL, *server_name = NULL;
505     krb5_error_code ret = 0;
506     const char *e_text = NULL;
507     krb5_crypto crypto;
508     Key *ckey, *skey;
509
510     memset(&rep, 0, sizeof(rep));
511
512     if(b->sname == NULL){
513         ret = KRB5KRB_ERR_GENERIC;
514         e_text = "No server in request";
515     } else{
516         principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
517         krb5_unparse_name(context, server_princ, &server_name);
518     }
519     if (ret) {
520         kdc_log(0, "AS-REQ malformed server name from %s", from);
521         goto out;
522     }
523     
524     if(b->cname == NULL){
525         ret = KRB5KRB_ERR_GENERIC;
526         e_text = "No client in request";
527     } else {
528         principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
529         krb5_unparse_name(context, client_princ, &client_name);
530     }
531     if (ret) {
532         kdc_log(0, "AS-REQ malformed client name from %s", from);
533         goto out;
534     }
535
536     kdc_log(0, "AS-REQ %s from %s for %s", client_name, from, server_name);
537
538     ret = db_fetch(client_princ, &client);
539     if(ret){
540         kdc_log(0, "UNKNOWN -- %s: %s", client_name,
541                 krb5_get_err_text(context, ret));
542         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
543         goto out;
544     }
545
546     ret = db_fetch(server_princ, &server);
547     if(ret){
548         kdc_log(0, "UNKNOWN -- %s: %s", server_name,
549                 krb5_get_err_text(context, ret));
550         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
551         goto out;
552     }
553
554     ret = check_flags(client, client_name, server, server_name, TRUE);
555     if(ret)
556         goto out;
557
558     memset(&et, 0, sizeof(et));
559     memset(&ek, 0, sizeof(ek));
560
561     if(req->padata){
562         int i = 0;
563         PA_DATA *pa;
564         int found_pa = 0;
565         kdc_log(5, "Looking for pa-data -- %s", client_name);
566         while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
567             krb5_data ts_data;
568             PA_ENC_TS_ENC p;
569             time_t patime;
570             size_t len;
571             EncryptedData enc_data;
572             Key *pa_key;
573             
574             found_pa = 1;
575             
576             ret = decode_EncryptedData(pa->padata_value.data,
577                                        pa->padata_value.length,
578                                        &enc_data,
579                                        &len);
580             if (ret) {
581                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
582                 kdc_log(5, "Failed to decode PA-DATA -- %s", 
583                         client_name);
584                 goto out;
585             }
586             
587             ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
588             if(ret){
589                 char *estr;
590                 e_text = "No key matches pa-data";
591                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
592                 if(krb5_enctype_to_string(context, enc_data.etype, &estr))
593                     estr = NULL;
594                 if(estr == NULL)
595                     kdc_log(5, "No client key matching pa-data (%d) -- %s", 
596                             enc_data.etype, client_name);
597                 else
598                     kdc_log(5, "No client key matching pa-data (%s) -- %s", 
599                             estr, client_name);
600                 free(estr);
601                     
602                 free_EncryptedData(&enc_data);
603                 continue;
604             }
605
606           try_next_key:
607             ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
608             if (ret) {
609                 kdc_log(0, "krb5_crypto_init failed: %s",
610                         krb5_get_err_text(context, ret));
611                 free_EncryptedData(&enc_data);
612                 continue;
613             }
614
615             ret = krb5_decrypt_EncryptedData (context,
616                                               crypto,
617                                               KRB5_KU_PA_ENC_TIMESTAMP,
618                                               &enc_data,
619                                               &ts_data);
620             krb5_crypto_destroy(context, crypto);
621             if(ret){
622                 if(hdb_next_enctype2key(context, client, 
623                                         enc_data.etype, &pa_key) == 0)
624                     goto try_next_key;
625                 free_EncryptedData(&enc_data);
626                 e_text = "Failed to decrypt PA-DATA";
627                 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
628                          client_name);
629                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
630                 continue;
631             }
632             free_EncryptedData(&enc_data);
633             ret = decode_PA_ENC_TS_ENC(ts_data.data,
634                                        ts_data.length,
635                                        &p,
636                                        &len);
637             krb5_data_free(&ts_data);
638             if(ret){
639                 e_text = "Failed to decode PA-ENC-TS-ENC";
640                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
641                 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
642                          client_name);
643                 continue;
644             }
645             patime = p.patimestamp;
646             free_PA_ENC_TS_ENC(&p);
647             if (abs(kdc_time - p.patimestamp) > context->max_skew) {
648                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
649                 e_text = "Too large time skew";
650                 kdc_log(0, "Too large time skew -- %s", client_name);
651                 goto out;
652             }
653             et.flags.pre_authent = 1;
654             kdc_log(2, "Pre-authentication succeded -- %s", client_name);
655             break;
656         }
657         if(found_pa == 0 && require_preauth)
658             goto use_pa;
659         /* We come here if we found a pa-enc-timestamp, but if there
660            was some problem with it, other than too large skew */
661         if(found_pa && et.flags.pre_authent == 0){
662             kdc_log(0, "%s -- %s", e_text, client_name);
663             e_text = NULL;
664             goto out;
665         }
666     }else if (require_preauth
667               || client->flags.require_preauth
668               || server->flags.require_preauth) {
669         METHOD_DATA method_data;
670         PA_DATA *pa;
671         unsigned char *buf;
672         size_t len;
673         krb5_data foo_data;
674
675       use_pa: 
676         method_data.len = 0;
677         method_data.val = NULL;
678
679         ret = realloc_method_data(&method_data);
680         pa = &method_data.val[method_data.len-1];
681         pa->padata_type         = KRB5_PADATA_ENC_TIMESTAMP;
682         pa->padata_value.length = 0;
683         pa->padata_value.data   = NULL;
684
685         ret = get_pa_etype_info(&method_data, client, 
686                                 b->etype.val, b->etype.len); /* XXX check ret */
687         
688         ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
689         free_METHOD_DATA(&method_data);
690         foo_data.data   = buf;
691         foo_data.length = len;
692         
693         ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
694         krb5_mk_error(context,
695                       ret,
696                       "Need to use PA-ENC-TIMESTAMP",
697                       &foo_data,
698                       client_princ,
699                       server_princ,
700                       NULL,
701                       NULL,
702                       reply);
703         free(buf);
704         kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
705         ret = 0;
706         goto out2;
707     }
708     
709     ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
710                     b->etype.val, b->etype.len);
711     if(ret) {
712         kdc_log(0, "Server/client has no support for etypes");
713         goto out;
714     }
715         
716     {
717         char *cet;
718         char *set;
719
720         ret = krb5_enctype_to_string(context, cetype, &cet);
721         if(ret == 0) {
722             ret = krb5_enctype_to_string(context, setype, &set);
723             if (ret == 0) {
724                 kdc_log(5, "Using %s/%s", cet, set);
725                 free(set);
726             }
727             free(cet);
728         }
729         if (ret != 0)
730             kdc_log(5, "Using e-types %d/%d", cetype, setype);
731     }
732     
733     {
734         char str[128];
735         unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
736         if(*str)
737             kdc_log(2, "Requested flags: %s", str);
738     }
739     
740
741     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
742        || (f.request_anonymous && !allow_anonymous)) {
743         ret = KRB5KDC_ERR_BADOPTION;
744         kdc_log(0, "Bad KDC options -- %s", client_name);
745         goto out;
746     }
747     
748     rep.pvno = 5;
749     rep.msg_type = krb_as_rep;
750     copy_Realm(&b->realm, &rep.crealm);
751     if (f.request_anonymous)
752         make_anonymous_principalname (&rep.cname);
753     else
754         copy_PrincipalName(b->cname, &rep.cname);
755     rep.ticket.tkt_vno = 5;
756     copy_Realm(&b->realm, &rep.ticket.realm);
757     copy_PrincipalName(b->sname, &rep.ticket.sname);
758
759     et.flags.initial = 1;
760     if(client->flags.forwardable && server->flags.forwardable)
761         et.flags.forwardable = f.forwardable;
762     else if (f.forwardable) {
763         ret = KRB5KDC_ERR_POLICY;
764         kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
765         goto out;
766     }
767     if(client->flags.proxiable && server->flags.proxiable)
768         et.flags.proxiable = f.proxiable;
769     else if (f.proxiable) {
770         ret = KRB5KDC_ERR_POLICY;
771         kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
772         goto out;
773     }
774     if(client->flags.postdate && server->flags.postdate)
775         et.flags.may_postdate = f.allow_postdate;
776     else if (f.allow_postdate){
777         ret = KRB5KDC_ERR_POLICY;
778         kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
779         goto out;
780     }
781
782     /* check for valid set of addresses */
783     if(!check_addresses(b->addresses, from_addr)) {
784         ret = KRB5KRB_AP_ERR_BADADDR;
785         kdc_log(0, "Bad address list requested -- %s", client_name);
786         goto out;
787     }
788
789     krb5_generate_random_keyblock(context, setype, &et.key);
790     copy_PrincipalName(&rep.cname, &et.cname);
791     copy_Realm(&b->realm, &et.crealm);
792     
793     {
794         time_t start;
795         time_t t;
796         
797         start = et.authtime = kdc_time;
798     
799         if(f.postdated && req->req_body.from){
800             ALLOC(et.starttime);
801             start = *et.starttime = *req->req_body.from;
802             et.flags.invalid = 1;
803             et.flags.postdated = 1; /* XXX ??? */
804         }
805         fix_time(&b->till);
806         t = *b->till;
807
808         /* be careful not overflowing */
809
810         if(client->max_life)
811             t = start + min(t - start, *client->max_life);
812         if(server->max_life)
813             t = start + min(t - start, *server->max_life);
814 #if 0
815         t = min(t, start + realm->max_life);
816 #endif
817         et.endtime = t;
818         if(f.renewable_ok && et.endtime < *b->till){
819             f.renewable = 1;
820             if(b->rtime == NULL){
821                 ALLOC(b->rtime);
822                 *b->rtime = 0;
823             }
824             if(*b->rtime < *b->till)
825                 *b->rtime = *b->till;
826         }
827         if(f.renewable && b->rtime){
828             t = *b->rtime;
829             if(t == 0)
830                 t = MAX_TIME;
831             if(client->max_renew)
832                 t = start + min(t - start, *client->max_renew);
833             if(server->max_renew)
834                 t = start + min(t - start, *server->max_renew);
835 #if 0
836             t = min(t, start + realm->max_renew);
837 #endif
838             ALLOC(et.renew_till);
839             *et.renew_till = t;
840             et.flags.renewable = 1;
841         }
842     }
843
844     if (f.request_anonymous)
845         et.flags.anonymous = 1;
846     
847     if(b->addresses){
848         ALLOC(et.caddr);
849         copy_HostAddresses(b->addresses, et.caddr);
850     }
851     
852     et.transited.tr_type = DOMAIN_X500_COMPRESS;
853     krb5_data_zero(&et.transited.contents); 
854      
855     copy_EncryptionKey(&et.key, &ek.key);
856
857     /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
858      * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
859      * incapable of correctly decoding SEQUENCE OF's of zero length.
860      *
861      * To fix this, always send at least one no-op last_req
862      *
863      * If there's a pw_end or valid_end we will use that,
864      * otherwise just a dummy lr.
865      */
866     ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
867     ek.last_req.len = 0;
868     if (client->pw_end
869         && (kdc_warn_pwexpire == 0
870             || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
871         ek.last_req.val[ek.last_req.len].lr_type  = LR_PW_EXPTIME;
872         ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
873         ++ek.last_req.len;
874     }
875     if (client->valid_end) {
876         ek.last_req.val[ek.last_req.len].lr_type  = LR_ACCT_EXPTIME;
877         ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
878         ++ek.last_req.len;
879     }
880     if (ek.last_req.len == 0) {
881         ek.last_req.val[ek.last_req.len].lr_type  = LR_NONE;
882         ek.last_req.val[ek.last_req.len].lr_value = 0;
883         ++ek.last_req.len;
884     }
885     ek.nonce = b->nonce;
886     if (client->valid_end || client->pw_end) {
887         ALLOC(ek.key_expiration);
888         if (client->valid_end) {
889             if (client->pw_end)
890                 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
891             else
892                 *ek.key_expiration = *client->valid_end;
893         } else
894             *ek.key_expiration = *client->pw_end;
895     } else
896         ek.key_expiration = NULL;
897     ek.flags = et.flags;
898     ek.authtime = et.authtime;
899     if (et.starttime) {
900         ALLOC(ek.starttime);
901         *ek.starttime = *et.starttime;
902     }
903     ek.endtime = et.endtime;
904     if (et.renew_till) {
905         ALLOC(ek.renew_till);
906         *ek.renew_till = *et.renew_till;
907     }
908     copy_Realm(&rep.ticket.realm, &ek.srealm);
909     copy_PrincipalName(&rep.ticket.sname, &ek.sname);
910     if(et.caddr){
911         ALLOC(ek.caddr);
912         copy_HostAddresses(et.caddr, ek.caddr);
913     }
914
915     set_salt_padata (&rep.padata, ckey->salt);
916     ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
917                        client->kvno, &ckey->key, &e_text, reply);
918     free_EncTicketPart(&et);
919     free_EncKDCRepPart(&ek);
920   out:
921     free_AS_REP(&rep);
922     if(ret){
923         krb5_mk_error(context,
924                       ret,
925                       e_text,
926                       NULL,
927                       client_princ,
928                       server_princ,
929                       NULL,
930                       NULL,
931                       reply);
932         ret = 0;
933     }
934   out2:
935     if (client_princ)
936         krb5_free_principal(context, client_princ);
937     free(client_name);
938     if (server_princ)
939         krb5_free_principal(context, server_princ);
940     free(server_name);
941     if(client)
942         free_ent(client);
943     if(server)
944         free_ent(server);
945     return ret;
946 }
947
948
949 static krb5_error_code
950 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
951 {
952     KDCOptions f = b->kdc_options;
953         
954     if(f.validate){
955         if(!tgt->flags.invalid || tgt->starttime == NULL){
956             kdc_log(0, "Bad request to validate ticket");
957             return KRB5KDC_ERR_BADOPTION;
958         }
959         if(*tgt->starttime > kdc_time){
960             kdc_log(0, "Early request to validate ticket");
961             return KRB5KRB_AP_ERR_TKT_NYV;
962         }
963         /* XXX  tkt = tgt */
964         et->flags.invalid = 0;
965     }else if(tgt->flags.invalid){
966         kdc_log(0, "Ticket-granting ticket has INVALID flag set");
967         return KRB5KRB_AP_ERR_TKT_INVALID;
968     }
969
970     if(f.forwardable){
971         if(!tgt->flags.forwardable){
972             kdc_log(0, "Bad request for forwardable ticket");
973             return KRB5KDC_ERR_BADOPTION;
974         }
975         et->flags.forwardable = 1;
976     }
977     if(f.forwarded){
978         if(!tgt->flags.forwardable){
979             kdc_log(0, "Request to forward non-forwardable ticket");
980             return KRB5KDC_ERR_BADOPTION;
981         }
982         et->flags.forwarded = 1;
983         et->caddr = b->addresses;
984     }
985     if(tgt->flags.forwarded)
986         et->flags.forwarded = 1;
987         
988     if(f.proxiable){
989         if(!tgt->flags.proxiable){
990             kdc_log(0, "Bad request for proxiable ticket");
991             return KRB5KDC_ERR_BADOPTION;
992         }
993         et->flags.proxiable = 1;
994     }
995     if(f.proxy){
996         if(!tgt->flags.proxiable){
997             kdc_log(0, "Request to proxy non-proxiable ticket");
998             return KRB5KDC_ERR_BADOPTION;
999         }
1000         et->flags.proxy = 1;
1001         et->caddr = b->addresses;
1002     }
1003     if(tgt->flags.proxy)
1004         et->flags.proxy = 1;
1005
1006     if(f.allow_postdate){
1007         if(!tgt->flags.may_postdate){
1008             kdc_log(0, "Bad request for post-datable ticket");
1009             return KRB5KDC_ERR_BADOPTION;
1010         }
1011         et->flags.may_postdate = 1;
1012     }
1013     if(f.postdated){
1014         if(!tgt->flags.may_postdate){
1015             kdc_log(0, "Bad request for postdated ticket");
1016             return KRB5KDC_ERR_BADOPTION;
1017         }
1018         if(b->from)
1019             *et->starttime = *b->from;
1020         et->flags.postdated = 1;
1021         et->flags.invalid = 1;
1022     }else if(b->from && *b->from > kdc_time + context->max_skew){
1023         kdc_log(0, "Ticket cannot be postdated");
1024         return KRB5KDC_ERR_CANNOT_POSTDATE;
1025     }
1026
1027     if(f.renewable){
1028         if(!tgt->flags.renewable){
1029             kdc_log(0, "Bad request for renewable ticket");
1030             return KRB5KDC_ERR_BADOPTION;
1031         }
1032         et->flags.renewable = 1;
1033         ALLOC(et->renew_till);
1034         fix_time(&b->rtime);
1035         *et->renew_till = *b->rtime;
1036     }
1037     if(f.renew){
1038         time_t old_life;
1039         if(!tgt->flags.renewable || tgt->renew_till == NULL){
1040             kdc_log(0, "Request to renew non-renewable ticket");
1041             return KRB5KDC_ERR_BADOPTION;
1042         }
1043         old_life = tgt->endtime;
1044         if(tgt->starttime)
1045             old_life -= *tgt->starttime;
1046         else
1047             old_life -= tgt->authtime;
1048         et->endtime = *et->starttime + old_life;
1049         if (et->renew_till != NULL)
1050             et->endtime = min(*et->renew_till, et->endtime);
1051     }       
1052     
1053     /* checks for excess flags */
1054     if(f.request_anonymous && !allow_anonymous){
1055         kdc_log(0, "Request for anonymous ticket");
1056         return KRB5KDC_ERR_BADOPTION;
1057     }
1058     return 0;
1059 }
1060
1061 static krb5_error_code
1062 fix_transited_encoding(krb5_boolean check_policy,
1063                        TransitedEncoding *tr, 
1064                        EncTicketPart *et, 
1065                        const char *client_realm, 
1066                        const char *server_realm, 
1067                        const char *tgt_realm)
1068 {
1069     krb5_error_code ret = 0;
1070     char **realms, **tmp;
1071     int num_realms;
1072     int i;
1073
1074     if(tr->tr_type != DOMAIN_X500_COMPRESS) {
1075         kdc_log(0, "Unknown transited type: %u", tr->tr_type);
1076         return KRB5KDC_ERR_TRTYPE_NOSUPP;
1077     }
1078
1079     ret = krb5_domain_x500_decode(context, 
1080                                   tr->contents,
1081                                   &realms, 
1082                                   &num_realms,
1083                                   client_realm,
1084                                   server_realm);
1085     if(ret){
1086         krb5_warn(context, ret, "Decoding transited encoding");
1087         return ret;
1088     }
1089     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
1090         /* not us, so add the previous realm to transited set */
1091         if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
1092             ret = ERANGE;
1093             goto free_realms;
1094         }
1095         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1096         if(tmp == NULL){
1097             ret = ENOMEM;
1098             goto free_realms;
1099         }
1100         realms = tmp;
1101         realms[num_realms] = strdup(tgt_realm);
1102         if(realms[num_realms] == NULL){
1103             ret = ENOMEM;
1104             goto free_realms;
1105         }
1106         num_realms++;
1107     }
1108     if(num_realms == 0) {
1109         if(strcmp(client_realm, server_realm)) 
1110             kdc_log(0, "cross-realm %s -> %s", client_realm, server_realm);
1111     } else {
1112         size_t l = 0;
1113         char *rs;
1114         for(i = 0; i < num_realms; i++)
1115             l += strlen(realms[i]) + 2;
1116         rs = malloc(l);
1117         if(rs != NULL) {
1118             *rs = '\0';
1119             for(i = 0; i < num_realms; i++) {
1120                 if(i > 0)
1121                     strlcat(rs, ", ", l);
1122                 strlcat(rs, realms[i], l);
1123             }
1124             kdc_log(0, "cross-realm %s -> %s via [%s]", client_realm, server_realm, rs);
1125             free(rs);
1126         }
1127     }
1128     if(check_policy) {
1129         ret = krb5_check_transited(context, client_realm, 
1130                                    server_realm, 
1131                                    realms, num_realms, NULL);
1132         if(ret) {
1133             krb5_warn(context, ret, "cross-realm %s -> %s", 
1134                       client_realm, server_realm);
1135             goto free_realms;
1136         }
1137         et->flags.transited_policy_checked = 1;
1138     }
1139     et->transited.tr_type = DOMAIN_X500_COMPRESS;
1140     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
1141     if(ret)
1142         krb5_warn(context, ret, "Encoding transited encoding");
1143   free_realms:
1144     for(i = 0; i < num_realms; i++)
1145         free(realms[i]);
1146     free(realms);
1147     return ret;
1148 }
1149
1150
1151 static krb5_error_code
1152 tgs_make_reply(KDC_REQ_BODY *b, 
1153                EncTicketPart *tgt, 
1154                EncTicketPart *adtkt, 
1155                AuthorizationData *auth_data,
1156                hdb_entry *server, 
1157                hdb_entry *client, 
1158                krb5_principal client_principal, 
1159                hdb_entry *krbtgt,
1160                krb5_enctype cetype,
1161                const char **e_text,
1162                krb5_data *reply)
1163 {
1164     KDC_REP rep;
1165     EncKDCRepPart ek;
1166     EncTicketPart et;
1167     KDCOptions f = b->kdc_options;
1168     krb5_error_code ret;
1169     krb5_enctype etype;
1170     Key *skey;
1171     EncryptionKey *ekey;
1172     
1173     if(adtkt) {
1174         int i;
1175         krb5_keytype kt;
1176         ekey = &adtkt->key;
1177         for(i = 0; i < b->etype.len; i++){
1178             ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
1179             if(ret)
1180                 continue;
1181             if(adtkt->key.keytype == kt)
1182                 break;
1183         }
1184         if(i == b->etype.len)
1185             return KRB5KDC_ERR_ETYPE_NOSUPP;
1186         etype = b->etype.val[i];
1187     }else{
1188         ret = find_keys(NULL, server, NULL, NULL, &skey, &etype, 
1189                         b->etype.val, b->etype.len);
1190         if(ret) {
1191             kdc_log(0, "Server has no support for etypes");
1192             return ret;
1193         }
1194         ekey = &skey->key;
1195     }
1196     
1197     memset(&rep, 0, sizeof(rep));
1198     memset(&et, 0, sizeof(et));
1199     memset(&ek, 0, sizeof(ek));
1200     
1201     rep.pvno = 5;
1202     rep.msg_type = krb_tgs_rep;
1203
1204     et.authtime = tgt->authtime;
1205     fix_time(&b->till);
1206     et.endtime = min(tgt->endtime, *b->till);
1207     ALLOC(et.starttime);
1208     *et.starttime = kdc_time;
1209     
1210     ret = check_tgs_flags(b, tgt, &et);
1211     if(ret)
1212         goto out;
1213
1214     /* We should check the transited encoding if:
1215        1) the request doesn't ask not to be checked
1216        2) globally enforcing a check
1217        3) principal requires checking
1218        4) we allow non-check per-principal, but principal isn't marked as allowing this
1219        5) we don't globally allow this
1220     */
1221
1222 #define GLOBAL_FORCE_TRANSITED_CHECK            (trpolicy == TRPOLICY_ALWAYS_CHECK)
1223 #define GLOBAL_ALLOW_PER_PRINCIPAL              (trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
1224 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK    (trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
1225 /* these will consult the database in future release */
1226 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
1227 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
1228
1229     ret = fix_transited_encoding(!f.disable_transited_check ||
1230                                  GLOBAL_FORCE_TRANSITED_CHECK ||
1231                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
1232                                  !((GLOBAL_ALLOW_PER_PRINCIPAL && 
1233                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
1234                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
1235                                  &tgt->transited, &et,
1236                                  *krb5_princ_realm(context, client_principal),
1237                                  *krb5_princ_realm(context, server->principal),
1238                                  *krb5_princ_realm(context, krbtgt->principal));
1239     if(ret)
1240         goto out;
1241
1242     copy_Realm(krb5_princ_realm(context, server->principal), 
1243                &rep.ticket.realm);
1244     krb5_principal2principalname(&rep.ticket.sname, server->principal);
1245     copy_Realm(&tgt->crealm, &rep.crealm);
1246     if (f.request_anonymous)
1247         make_anonymous_principalname (&tgt->cname);
1248     else
1249         copy_PrincipalName(&tgt->cname, &rep.cname);
1250     rep.ticket.tkt_vno = 5;
1251
1252     ek.caddr = et.caddr;
1253     if(et.caddr == NULL)
1254         et.caddr = tgt->caddr;
1255
1256     {
1257         time_t life;
1258         life = et.endtime - *et.starttime;
1259         if(client && client->max_life)
1260             life = min(life, *client->max_life);
1261         if(server->max_life)
1262             life = min(life, *server->max_life);
1263         et.endtime = *et.starttime + life;
1264     }
1265     if(f.renewable_ok && tgt->flags.renewable && 
1266        et.renew_till == NULL && et.endtime < *b->till){
1267         et.flags.renewable = 1;
1268         ALLOC(et.renew_till);
1269         *et.renew_till = *b->till;
1270     }
1271     if(et.renew_till){
1272         time_t renew;
1273         renew = *et.renew_till - et.authtime;
1274         if(client && client->max_renew)
1275             renew = min(renew, *client->max_renew);
1276         if(server->max_renew)
1277             renew = min(renew, *server->max_renew);
1278         *et.renew_till = et.authtime + renew;
1279     }
1280             
1281     if(et.renew_till){
1282         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
1283         *et.starttime = min(*et.starttime, *et.renew_till);
1284         et.endtime = min(et.endtime, *et.renew_till);
1285     }
1286     
1287     *et.starttime = min(*et.starttime, et.endtime);
1288
1289     if(*et.starttime == et.endtime){
1290         ret = KRB5KDC_ERR_NEVER_VALID;
1291         goto out;
1292     }
1293     if(et.renew_till && et.endtime == *et.renew_till){
1294         free(et.renew_till);
1295         et.renew_till = NULL;
1296         et.flags.renewable = 0;
1297     }
1298     
1299     et.flags.pre_authent = tgt->flags.pre_authent;
1300     et.flags.hw_authent  = tgt->flags.hw_authent;
1301     et.flags.anonymous   = tgt->flags.anonymous;
1302             
1303     /* XXX Check enc-authorization-data */
1304     et.authorization_data = auth_data;
1305
1306     krb5_generate_random_keyblock(context, etype, &et.key);
1307     et.crealm = tgt->crealm;
1308     et.cname = tgt->cname;
1309             
1310     ek.key = et.key;
1311     /* MIT must have at least one last_req */
1312     ek.last_req.len = 1;
1313     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1314     ek.nonce = b->nonce;
1315     ek.flags = et.flags;
1316     ek.authtime = et.authtime;
1317     ek.starttime = et.starttime;
1318     ek.endtime = et.endtime;
1319     ek.renew_till = et.renew_till;
1320     ek.srealm = rep.ticket.realm;
1321     ek.sname = rep.ticket.sname;
1322             
1323     /* It is somewhat unclear where the etype in the following
1324        encryption should come from. What we have is a session
1325        key in the passed tgt, and a list of preferred etypes
1326        *for the new ticket*. Should we pick the best possible
1327        etype, given the keytype in the tgt, or should we look
1328        at the etype list here as well?  What if the tgt
1329        session key is DES3 and we want a ticket with a (say)
1330        CAST session key. Should the DES3 etype be added to the
1331        etype list, even if we don't want a session key with
1332        DES3? */
1333     ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
1334                        0, &tgt->key, e_text, reply);
1335   out:
1336     free_TGS_REP(&rep);
1337     free_TransitedEncoding(&et.transited);
1338     if(et.starttime)
1339         free(et.starttime);
1340     if(et.renew_till)
1341         free(et.renew_till);
1342     free_LastReq(&ek.last_req);
1343     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1344     free_EncryptionKey(&et.key);
1345     return ret;
1346 }
1347
1348 static krb5_error_code
1349 tgs_check_authenticator(krb5_auth_context ac,
1350                         KDC_REQ_BODY *b, 
1351                         const char **e_text,
1352                         krb5_keyblock *key)
1353 {
1354     krb5_authenticator auth;
1355     size_t len;
1356     unsigned char *buf;
1357     size_t buf_size;
1358     krb5_error_code ret;
1359     krb5_crypto crypto;
1360     
1361     krb5_auth_con_getauthenticator(context, ac, &auth);
1362     if(auth->cksum == NULL){
1363         kdc_log(0, "No authenticator in request");
1364         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1365         goto out;
1366     }
1367     /*
1368      * according to RFC1510 it doesn't need to be keyed,
1369      * but according to the latest draft it needs to.
1370      */
1371     if (
1372 #if 0
1373 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1374         ||
1375 #endif
1376  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1377         kdc_log(0, "Bad checksum type in authenticator: %d", 
1378                 auth->cksum->cksumtype);
1379         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1380         goto out;
1381     }
1382                 
1383     /* XXX should not re-encode this */
1384     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1385     if(ret){
1386         kdc_log(0, "Failed to encode KDC-REQ-BODY: %s", 
1387                 krb5_get_err_text(context, ret));
1388         goto out;
1389     }
1390     if(buf_size != len) {
1391         free(buf);
1392         kdc_log(0, "Internal error in ASN.1 encoder");
1393         *e_text = "KDC internal error";
1394         ret = KRB5KRB_ERR_GENERIC;
1395         goto out;
1396     }
1397     ret = krb5_crypto_init(context, key, 0, &crypto);
1398     if (ret) {
1399         free(buf);
1400         kdc_log(0, "krb5_crypto_init failed: %s",
1401                 krb5_get_err_text(context, ret));
1402         goto out;
1403     }
1404     ret = krb5_verify_checksum(context,
1405                                crypto,
1406                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
1407                                buf, 
1408                                len,
1409                                auth->cksum);
1410     free(buf);
1411     krb5_crypto_destroy(context, crypto);
1412     if(ret){
1413         kdc_log(0, "Failed to verify checksum: %s", 
1414                 krb5_get_err_text(context, ret));
1415     }
1416 out:
1417     free_Authenticator(auth);
1418     free(auth);
1419     return ret;
1420 }
1421
1422 /*
1423  * return the realm of a krbtgt-ticket or NULL
1424  */
1425
1426 static Realm 
1427 get_krbtgt_realm(const PrincipalName *p)
1428 {
1429     if(p->name_string.len == 2
1430        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
1431         return p->name_string.val[1];
1432     else
1433         return NULL;
1434 }
1435
1436 static Realm
1437 find_rpath(Realm crealm, Realm srealm)
1438 {
1439     const char *new_realm = krb5_config_get_string(context,
1440                                                    NULL,
1441                                                    "capaths", 
1442                                                    crealm,
1443                                                    srealm,
1444                                                    NULL);
1445     return (Realm)new_realm;
1446 }
1447             
1448
1449 static krb5_boolean
1450 need_referral(krb5_principal server, krb5_realm **realms)
1451 {
1452     if(server->name.name_type != KRB5_NT_SRV_INST ||
1453        server->name.name_string.len != 2)
1454         return FALSE;
1455  
1456     return krb5_get_host_realm_int(context, server->name.name_string.val[1],
1457                                    FALSE, realms) == 0;
1458 }
1459
1460 static krb5_error_code
1461 tgs_rep2(KDC_REQ_BODY *b,
1462          PA_DATA *tgs_req,
1463          krb5_data *reply,
1464          const char *from,
1465          const struct sockaddr *from_addr,
1466          time_t **csec,
1467          int **cusec)
1468 {
1469     krb5_ap_req ap_req;
1470     krb5_error_code ret;
1471     krb5_principal princ;
1472     krb5_auth_context ac = NULL;
1473     krb5_ticket *ticket = NULL;
1474     krb5_flags ap_req_options;
1475     krb5_flags verify_ap_req_flags;
1476     const char *e_text = NULL;
1477     krb5_crypto crypto;
1478
1479     hdb_entry *krbtgt = NULL;
1480     EncTicketPart *tgt;
1481     Key *tkey;
1482     krb5_enctype cetype;
1483     krb5_principal cp = NULL;
1484     krb5_principal sp = NULL;
1485     AuthorizationData *auth_data = NULL;
1486
1487     *csec  = NULL;
1488     *cusec = NULL;
1489
1490     memset(&ap_req, 0, sizeof(ap_req));
1491     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1492     if(ret){
1493         kdc_log(0, "Failed to decode AP-REQ: %s", 
1494                 krb5_get_err_text(context, ret));
1495         goto out2;
1496     }
1497     
1498     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1499         /* XXX check for ticket.sname == req.sname */
1500         kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1501         ret = KRB5KDC_ERR_POLICY; /* ? */
1502         goto out2;
1503     }
1504     
1505     principalname2krb5_principal(&princ,
1506                                  ap_req.ticket.sname,
1507                                  ap_req.ticket.realm);
1508     
1509     ret = db_fetch(princ, &krbtgt);
1510
1511     if(ret) {
1512         char *p;
1513         krb5_unparse_name(context, princ, &p);
1514         krb5_free_principal(context, princ);
1515         kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
1516                 p, krb5_get_err_text(context, ret));
1517         free(p);
1518         ret = KRB5KRB_AP_ERR_NOT_US;
1519         goto out2;
1520     }
1521     
1522     if(ap_req.ticket.enc_part.kvno && 
1523        *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
1524         char *p;
1525
1526         krb5_unparse_name (context, princ, &p);
1527         krb5_free_principal(context, princ);
1528         kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)", 
1529                 *ap_req.ticket.enc_part.kvno,
1530                 krbtgt->kvno,
1531                 p);
1532         free (p);
1533         ret = KRB5KRB_AP_ERR_BADKEYVER;
1534         goto out2;
1535     }
1536
1537     ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
1538     if(ret){
1539         char *str;
1540         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1541         kdc_log(0, "No server key found for %s", str);
1542         free(str);
1543         ret = KRB5KRB_AP_ERR_BADKEYVER;
1544         goto out2;
1545     }
1546     
1547     if (b->kdc_options.validate)
1548         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1549     else
1550         verify_ap_req_flags = 0;
1551
1552     ret = krb5_verify_ap_req2(context,
1553                               &ac,
1554                               &ap_req,
1555                               princ,
1556                               &tkey->key,
1557                               verify_ap_req_flags,
1558                               &ap_req_options,
1559                               &ticket,
1560                               KRB5_KU_TGS_REQ_AUTH);
1561                              
1562     krb5_free_principal(context, princ);
1563     if(ret) {
1564         kdc_log(0, "Failed to verify AP-REQ: %s", 
1565                 krb5_get_err_text(context, ret));
1566         goto out2;
1567     }
1568
1569     {
1570         krb5_authenticator auth;
1571
1572         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1573         if (ret == 0) {
1574             *csec   = malloc(sizeof(**csec));
1575             if (*csec == NULL) {
1576                 krb5_free_authenticator(context, &auth);
1577                 kdc_log(0, "malloc failed");
1578                 goto out2;
1579             }
1580             **csec  = auth->ctime;
1581             *cusec  = malloc(sizeof(**cusec));
1582             if (*cusec == NULL) {
1583                 krb5_free_authenticator(context, &auth);
1584                 kdc_log(0, "malloc failed");
1585                 goto out2;
1586             }
1587             **csec  = auth->cusec;
1588             krb5_free_authenticator(context, &auth);
1589         }
1590     }
1591
1592     cetype = ap_req.authenticator.etype;
1593
1594     tgt = &ticket->ticket;
1595
1596     ret = tgs_check_authenticator(ac, b, &e_text, &tgt->key);
1597
1598     if (b->enc_authorization_data) {
1599         krb5_keyblock *subkey;
1600         krb5_data ad;
1601         ret = krb5_auth_con_getremotesubkey(context,
1602                                             ac,
1603                                             &subkey);
1604         if(ret){
1605             krb5_auth_con_free(context, ac);
1606             kdc_log(0, "Failed to get remote subkey: %s", 
1607                     krb5_get_err_text(context, ret));
1608             goto out2;
1609         }
1610         if(subkey == NULL){
1611             ret = krb5_auth_con_getkey(context, ac, &subkey);
1612             if(ret) {
1613                 krb5_auth_con_free(context, ac);
1614                 kdc_log(0, "Failed to get session key: %s", 
1615                         krb5_get_err_text(context, ret));
1616                 goto out2;
1617             }
1618         }
1619         if(subkey == NULL){
1620             krb5_auth_con_free(context, ac);
1621             kdc_log(0, "Failed to get key for enc-authorization-data");
1622             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1623             goto out2;
1624         }
1625         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1626         if (ret) {
1627             krb5_auth_con_free(context, ac);
1628             kdc_log(0, "krb5_crypto_init failed: %s",
1629                     krb5_get_err_text(context, ret));
1630             goto out2;
1631         }
1632         ret = krb5_decrypt_EncryptedData (context,
1633                                           crypto,
1634                                           KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1635                                           b->enc_authorization_data,
1636                                           &ad);
1637         krb5_crypto_destroy(context, crypto);
1638         if(ret){
1639             krb5_auth_con_free(context, ac);
1640             kdc_log(0, "Failed to decrypt enc-authorization-data");
1641             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1642             goto out2;
1643         }
1644         krb5_free_keyblock(context, subkey);
1645         ALLOC(auth_data);
1646         ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1647         if(ret){
1648             krb5_auth_con_free(context, ac);
1649             free(auth_data);
1650             auth_data = NULL;
1651             kdc_log(0, "Failed to decode authorization data");
1652             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1653             goto out2;
1654         }
1655     }
1656
1657     krb5_auth_con_free(context, ac);
1658
1659     if(ret){
1660         kdc_log(0, "Failed to verify authenticator: %s", 
1661                 krb5_get_err_text(context, ret));
1662         goto out2;
1663     }
1664     
1665     {
1666         PrincipalName *s;
1667         Realm r;
1668         char *spn = NULL, *cpn = NULL;
1669         hdb_entry *server = NULL, *client = NULL;
1670         int loop = 0;
1671         EncTicketPart adtkt;
1672         char opt_str[128];
1673
1674         s = b->sname;
1675         r = b->realm;
1676         if(b->kdc_options.enc_tkt_in_skey){
1677             Ticket *t;
1678             hdb_entry *uu;
1679             krb5_principal p;
1680             Key *tkey;
1681             
1682             if(b->additional_tickets == NULL || 
1683                b->additional_tickets->len == 0){
1684                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1685                 kdc_log(0, "No second ticket present in request");
1686                 goto out;
1687             }
1688             t = &b->additional_tickets->val[0];
1689             if(!get_krbtgt_realm(&t->sname)){
1690                 kdc_log(0, "Additional ticket is not a ticket-granting ticket");
1691                 ret = KRB5KDC_ERR_POLICY;
1692                 goto out2;
1693             }
1694             principalname2krb5_principal(&p, t->sname, t->realm);
1695             ret = db_fetch(p, &uu);
1696             krb5_free_principal(context, p);
1697             if(ret){
1698                 if (ret == HDB_ERR_NOENTRY)
1699                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1700                 goto out;
1701             }
1702             ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
1703             if(ret){
1704                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1705                 goto out;
1706             }
1707             ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0);
1708
1709             if(ret)
1710                 goto out;
1711             s = &adtkt.cname;
1712             r = adtkt.crealm;
1713         }
1714
1715         principalname2krb5_principal(&sp, *s, r);
1716         krb5_unparse_name(context, sp, &spn);   
1717         principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1718         krb5_unparse_name(context, cp, &cpn);
1719         unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
1720                        opt_str, sizeof(opt_str));
1721         if(*opt_str)
1722             kdc_log(0, "TGS-REQ %s from %s for %s [%s]", 
1723                     cpn, from, spn, opt_str);
1724         else
1725             kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1726     server_lookup:
1727         ret = db_fetch(sp, &server);
1728
1729         if(ret){
1730             Realm req_rlm, new_rlm;
1731             krb5_realm *realms;
1732
1733             if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1734                 if(loop++ < 2) {
1735                     new_rlm = find_rpath(tgt->crealm, req_rlm);
1736                     if(new_rlm) {
1737                         kdc_log(5, "krbtgt for realm %s not found, trying %s", 
1738                                 req_rlm, new_rlm);
1739                         krb5_free_principal(context, sp);
1740                         free(spn);
1741                         krb5_make_principal(context, &sp, r, 
1742                                             KRB5_TGS_NAME, new_rlm, NULL);
1743                         krb5_unparse_name(context, sp, &spn);   
1744                         goto server_lookup;
1745                     }
1746                 }
1747             } else if(need_referral(sp, &realms)) {
1748                 if (strcmp(realms[0], sp->realm) != 0) {
1749                     kdc_log(5, "returning a referral to realm %s for "
1750                             "server %s that was not found",
1751                             realms[0], spn);
1752                     krb5_free_principal(context, sp);
1753                     free(spn);
1754                     krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1755                                         realms[0], NULL);
1756                     krb5_unparse_name(context, sp, &spn);
1757                     krb5_free_host_realm(context, realms);
1758                     goto server_lookup;
1759                 }
1760                 krb5_free_host_realm(context, realms);
1761             }
1762             kdc_log(0, "Server not found in database: %s: %s", spn,
1763                     krb5_get_err_text(context, ret));
1764             if (ret == HDB_ERR_NOENTRY)
1765                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1766             goto out;
1767         }
1768
1769         ret = db_fetch(cp, &client);
1770         if(ret)
1771             kdc_log(1, "Client not found in database: %s: %s",
1772                     cpn, krb5_get_err_text(context, ret));
1773 #if 0
1774         /* XXX check client only if same realm as krbtgt-instance */
1775         if(ret){
1776             kdc_log(0, "Client not found in database: %s: %s",
1777                     cpn, krb5_get_err_text(context, ret));
1778             if (ret == HDB_ERR_NOENTRY)
1779                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1780             goto out;
1781         }
1782 #endif
1783
1784         if(strcmp(krb5_principal_get_realm(context, sp),
1785                   krb5_principal_get_comp_string(context, krbtgt->principal, 1)) != 0) {
1786             char *tpn;
1787             ret = krb5_unparse_name(context, krbtgt->principal, &tpn);
1788             kdc_log(0, "Request with wrong krbtgt: %s", (ret == 0) ? tpn : "<unknown>");
1789             if(ret == 0)
1790                 free(tpn);
1791             ret = KRB5KRB_AP_ERR_NOT_US;
1792             goto out;
1793             
1794         }
1795
1796         ret = check_flags(client, cpn, server, spn, FALSE);
1797         if(ret)
1798             goto out;
1799
1800         if((b->kdc_options.validate || b->kdc_options.renew) && 
1801            !krb5_principal_compare(context, 
1802                                    krbtgt->principal,
1803                                    server->principal)){
1804             kdc_log(0, "Inconsistent request.");
1805             ret = KRB5KDC_ERR_SERVER_NOMATCH;
1806             goto out;
1807         }
1808
1809         /* check for valid set of addresses */
1810         if(!check_addresses(tgt->caddr, from_addr)) {
1811             ret = KRB5KRB_AP_ERR_BADADDR;
1812             kdc_log(0, "Request from wrong address");
1813             goto out;
1814         }
1815         
1816         ret = tgs_make_reply(b, 
1817                              tgt, 
1818                              b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
1819                              auth_data,
1820                              server, 
1821                              client, 
1822                              cp, 
1823                              krbtgt, 
1824                              cetype, 
1825                              &e_text,
1826                              reply);
1827         
1828     out:
1829         free(spn);
1830         free(cpn);
1831             
1832         if(server)
1833             free_ent(server);
1834         if(client)
1835             free_ent(client);
1836     }
1837 out2:
1838     if(ret) {
1839         krb5_mk_error(context,
1840                       ret,
1841                       e_text,
1842                       NULL,
1843                       cp,
1844                       sp,
1845                       NULL,
1846                       NULL,
1847                       reply);
1848         free(*csec);
1849         free(*cusec);
1850         *csec  = NULL;
1851         *cusec = NULL;
1852     }
1853     krb5_free_principal(context, cp);
1854     krb5_free_principal(context, sp);
1855     if (ticket) {
1856         krb5_free_ticket(context, ticket);
1857         free(ticket);
1858     }
1859     free_AP_REQ(&ap_req);
1860     if(auth_data){
1861         free_AuthorizationData(auth_data);
1862         free(auth_data);
1863     }
1864
1865     if(krbtgt)
1866         free_ent(krbtgt);
1867
1868     return ret;
1869 }
1870
1871
1872 krb5_error_code
1873 tgs_rep(KDC_REQ *req, 
1874         krb5_data *data,
1875         const char *from,
1876         struct sockaddr *from_addr)
1877 {
1878     krb5_error_code ret;
1879     int i = 0;
1880     PA_DATA *tgs_req = NULL;
1881     time_t *csec = NULL;
1882     int *cusec = NULL;
1883
1884     if(req->padata == NULL){
1885         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1886         kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1887         goto out;
1888     }
1889     
1890     tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1891
1892     if(tgs_req == NULL){
1893         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1894         
1895         kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1896         goto out;
1897     }
1898     ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr,
1899                    &csec, &cusec);
1900 out:
1901     if(ret && data->data == NULL){
1902         krb5_mk_error(context,
1903                       ret,
1904                       NULL,
1905                       NULL,
1906                       NULL,
1907                       NULL,
1908                       csec,
1909                       cusec,
1910                       data);
1911     }
1912     free(csec);
1913     free(cusec);
1914     return 0;
1915 }