Merge from vendor branch BSDTAR:
[dragonfly.git] / crypto / heimdal / kdc / kerberos5.c
1 /*
2  * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "kdc_locl.h"
35
36 RCSID("$Id: kerberos5.c,v 1.143 2002/09/09 14:03:02 nectar 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 < client->keys.len; i++) {
335             if(client->keys.val[i].key.keytype == etypes[j])
336                 if((ret = make_etype_info_entry(&pa.val[n++], 
337                                                 &client->keys.val[i])) != 0) {
338                     free_ETYPE_INFO(&pa);
339                     return ret;
340                 }
341         }
342     }
343     for(i = 0; i < client->keys.len; i++) {
344         for(j = 0; j < etypes_len; j++) {
345             if(client->keys.val[i].key.keytype == etypes[j])
346                 goto skip;
347         }
348         if((ret = make_etype_info_entry(&pa.val[n++], 
349                                         &client->keys.val[i])) != 0) {
350             free_ETYPE_INFO(&pa);
351             return ret;
352         }
353       skip:;
354     }
355     
356     if(n != pa.len) {
357         char *name;
358         krb5_unparse_name(context, client->principal, &name);
359         kdc_log(0, "internal error in get_pa_etype_info(%s): %d != %d", 
360                 name, n, pa.len);
361         free(name);
362         pa.len = n;
363     }
364
365     ASN1_MALLOC_ENCODE(ETYPE_INFO, buf, len, &pa, &len, ret);
366     free_ETYPE_INFO(&pa);
367     if(ret)
368         return ret;
369     ret = realloc_method_data(md);
370     if(ret) {
371         free(buf);
372         return ret;
373     }
374     md->val[md->len - 1].padata_type = KRB5_PADATA_ETYPE_INFO;
375     md->val[md->len - 1].padata_value.length = len;
376     md->val[md->len - 1].padata_value.data = buf;
377     return 0;
378 }
379
380 /*
381  * verify the flags on `client' and `server', returning 0
382  * if they are OK and generating an error messages and returning
383  * and error code otherwise.
384  */
385
386 krb5_error_code
387 check_flags(hdb_entry *client, const char *client_name,
388             hdb_entry *server, const char *server_name,
389             krb5_boolean is_as_req)
390 {
391     if(client != NULL) {
392         /* check client */
393         if (client->flags.invalid) {
394             kdc_log(0, "Client (%s) has invalid bit set", client_name);
395             return KRB5KDC_ERR_POLICY;
396         }
397         
398         if(!client->flags.client){
399             kdc_log(0, "Principal may not act as client -- %s", 
400                     client_name);
401             return KRB5KDC_ERR_POLICY;
402         }
403         
404         if (client->valid_start && *client->valid_start > kdc_time) {
405             kdc_log(0, "Client not yet valid -- %s", client_name);
406             return KRB5KDC_ERR_CLIENT_NOTYET;
407         }
408         
409         if (client->valid_end && *client->valid_end < kdc_time) {
410             kdc_log(0, "Client expired -- %s", client_name);
411             return KRB5KDC_ERR_NAME_EXP;
412         }
413         
414         if (client->pw_end && *client->pw_end < kdc_time
415             && !server->flags.change_pw) {
416             kdc_log(0, "Client's key has expired -- %s", client_name);
417             return KRB5KDC_ERR_KEY_EXPIRED;
418         }
419     }
420
421     /* check server */
422     
423     if (server != NULL) {
424         if (server->flags.invalid) {
425             kdc_log(0, "Server has invalid flag set -- %s", server_name);
426             return KRB5KDC_ERR_POLICY;
427         }
428
429         if(!server->flags.server){
430             kdc_log(0, "Principal may not act as server -- %s", 
431                     server_name);
432             return KRB5KDC_ERR_POLICY;
433         }
434
435         if(!is_as_req && server->flags.initial) {
436             kdc_log(0, "AS-REQ is required for server -- %s", server_name);
437             return KRB5KDC_ERR_POLICY;
438         }
439
440         if (server->valid_start && *server->valid_start > kdc_time) {
441             kdc_log(0, "Server not yet valid -- %s", server_name);
442             return KRB5KDC_ERR_SERVICE_NOTYET;
443         }
444
445         if (server->valid_end && *server->valid_end < kdc_time) {
446             kdc_log(0, "Server expired -- %s", server_name);
447             return KRB5KDC_ERR_SERVICE_EXP;
448         }
449
450         if (server->pw_end && *server->pw_end < kdc_time) {
451             kdc_log(0, "Server's key has expired -- %s", server_name);
452             return KRB5KDC_ERR_KEY_EXPIRED;
453         }
454     }
455     return 0;
456 }
457
458 /*
459  * Return TRUE if `from' is part of `addresses' taking into consideration
460  * the configuration variables that tells us how strict we should be about
461  * these checks
462  */
463
464 static krb5_boolean
465 check_addresses(HostAddresses *addresses, const struct sockaddr *from)
466 {
467     krb5_error_code ret;
468     krb5_address addr;
469     krb5_boolean result;
470     
471     if(check_ticket_addresses == 0)
472         return TRUE;
473
474     if(addresses == NULL)
475         return allow_null_ticket_addresses;
476     
477     ret = krb5_sockaddr2address (context, from, &addr);
478     if(ret)
479         return FALSE;
480
481     result = krb5_address_search(context, &addr, addresses);
482     krb5_free_address (context, &addr);
483     return result;
484 }
485
486 krb5_error_code
487 as_rep(KDC_REQ *req, 
488        krb5_data *reply,
489        const char *from,
490        struct sockaddr *from_addr)
491 {
492     KDC_REQ_BODY *b = &req->req_body;
493     AS_REP rep;
494     KDCOptions f = b->kdc_options;
495     hdb_entry *client = NULL, *server = NULL;
496     krb5_enctype cetype, setype;
497     EncTicketPart et;
498     EncKDCRepPart ek;
499     krb5_principal client_princ, server_princ;
500     char *client_name, *server_name;
501     krb5_error_code ret = 0;
502     const char *e_text = NULL;
503     krb5_crypto crypto;
504     Key *ckey, *skey;
505
506     memset(&rep, 0, sizeof(rep));
507
508     if(b->sname == NULL){
509         server_name = "<unknown server>";
510         ret = KRB5KRB_ERR_GENERIC;
511         e_text = "No server in request";
512     } else{
513         principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
514         krb5_unparse_name(context, server_princ, &server_name);
515     }
516     
517     if(b->cname == NULL){
518         client_name = "<unknown client>";
519         ret = KRB5KRB_ERR_GENERIC;
520         e_text = "No client in request";
521     } else {
522         principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
523         krb5_unparse_name(context, client_princ, &client_name);
524     }
525     kdc_log(0, "AS-REQ %s from %s for %s", 
526             client_name, from, server_name);
527
528     if(ret)
529         goto out;
530
531     ret = db_fetch(client_princ, &client);
532     if(ret){
533         kdc_log(0, "UNKNOWN -- %s: %s", client_name,
534                 krb5_get_err_text(context, ret));
535         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
536         goto out;
537     }
538
539     ret = db_fetch(server_princ, &server);
540     if(ret){
541         kdc_log(0, "UNKNOWN -- %s: %s", server_name,
542                 krb5_get_err_text(context, ret));
543         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
544         goto out;
545     }
546
547     ret = check_flags(client, client_name, server, server_name, TRUE);
548     if(ret)
549         goto out;
550
551     memset(&et, 0, sizeof(et));
552     memset(&ek, 0, sizeof(ek));
553
554     if(req->padata){
555         int i = 0;
556         PA_DATA *pa;
557         int found_pa = 0;
558         kdc_log(5, "Looking for pa-data -- %s", client_name);
559         while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
560             krb5_data ts_data;
561             PA_ENC_TS_ENC p;
562             time_t patime;
563             size_t len;
564             EncryptedData enc_data;
565             Key *pa_key;
566             
567             found_pa = 1;
568             
569             ret = decode_EncryptedData(pa->padata_value.data,
570                                        pa->padata_value.length,
571                                        &enc_data,
572                                        &len);
573             if (ret) {
574                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
575                 kdc_log(5, "Failed to decode PA-DATA -- %s", 
576                         client_name);
577                 goto out;
578             }
579             
580             ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
581             if(ret){
582                 char *estr;
583                 e_text = "No key matches pa-data";
584                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
585                 if(krb5_enctype_to_string(context, enc_data.etype, &estr))
586                     estr = NULL;
587                 if(estr == NULL)
588                     kdc_log(5, "No client key matching pa-data (%d) -- %s", 
589                             enc_data.etype, client_name);
590                 else
591                     kdc_log(5, "No client key matching pa-data (%s) -- %s", 
592                             estr, client_name);
593                 free(estr);
594                     
595                 free_EncryptedData(&enc_data);
596                 continue;
597             }
598
599           try_next_key:
600             ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
601             if (ret) {
602                 kdc_log(0, "krb5_crypto_init failed: %s",
603                         krb5_get_err_text(context, ret));
604                 free_EncryptedData(&enc_data);
605                 continue;
606             }
607
608             ret = krb5_decrypt_EncryptedData (context,
609                                               crypto,
610                                               KRB5_KU_PA_ENC_TIMESTAMP,
611                                               &enc_data,
612                                               &ts_data);
613             krb5_crypto_destroy(context, crypto);
614             if(ret){
615                 if(hdb_next_enctype2key(context, client, 
616                                         enc_data.etype, &pa_key) == 0)
617                     goto try_next_key;
618                 free_EncryptedData(&enc_data);
619                 e_text = "Failed to decrypt PA-DATA";
620                 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
621                          client_name);
622                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
623                 continue;
624             }
625             free_EncryptedData(&enc_data);
626             ret = decode_PA_ENC_TS_ENC(ts_data.data,
627                                        ts_data.length,
628                                        &p,
629                                        &len);
630             krb5_data_free(&ts_data);
631             if(ret){
632                 e_text = "Failed to decode PA-ENC-TS-ENC";
633                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
634                 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
635                          client_name);
636                 continue;
637             }
638             patime = p.patimestamp;
639             free_PA_ENC_TS_ENC(&p);
640             if (abs(kdc_time - p.patimestamp) > context->max_skew) {
641                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
642                 e_text = "Too large time skew";
643                 kdc_log(0, "Too large time skew -- %s", client_name);
644                 goto out;
645             }
646             et.flags.pre_authent = 1;
647             kdc_log(2, "Pre-authentication succeded -- %s", client_name);
648             break;
649         }
650         if(found_pa == 0 && require_preauth)
651             goto use_pa;
652         /* We come here if we found a pa-enc-timestamp, but if there
653            was some problem with it, other than too large skew */
654         if(found_pa && et.flags.pre_authent == 0){
655             kdc_log(0, "%s -- %s", e_text, client_name);
656             e_text = NULL;
657             goto out;
658         }
659     }else if (require_preauth
660               || client->flags.require_preauth
661               || server->flags.require_preauth) {
662         METHOD_DATA method_data;
663         PA_DATA *pa;
664         unsigned char *buf;
665         size_t len;
666         krb5_data foo_data;
667
668       use_pa: 
669         method_data.len = 0;
670         method_data.val = NULL;
671
672         ret = realloc_method_data(&method_data);
673         pa = &method_data.val[method_data.len-1];
674         pa->padata_type         = KRB5_PADATA_ENC_TIMESTAMP;
675         pa->padata_value.length = 0;
676         pa->padata_value.data   = NULL;
677
678         ret = get_pa_etype_info(&method_data, client, 
679                                 b->etype.val, b->etype.len); /* XXX check ret */
680         
681         ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
682         free_METHOD_DATA(&method_data);
683         foo_data.data   = buf;
684         foo_data.length = len;
685         
686         ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
687         krb5_mk_error(context,
688                       ret,
689                       "Need to use PA-ENC-TIMESTAMP",
690                       &foo_data,
691                       client_princ,
692                       server_princ,
693                       NULL,
694                       NULL,
695                       reply);
696         free(buf);
697         kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
698         ret = 0;
699         goto out2;
700     }
701     
702     ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
703                     b->etype.val, b->etype.len);
704     if(ret) {
705         kdc_log(0, "Server/client has no support for etypes");
706         goto out;
707     }
708         
709     {
710         char *cet;
711         char *set;
712
713         ret = krb5_enctype_to_string(context, cetype, &cet);
714         if(ret == 0) {
715             ret = krb5_enctype_to_string(context, setype, &set);
716             if (ret == 0) {
717                 kdc_log(5, "Using %s/%s", cet, set);
718                 free(set);
719             } else
720                 free(cet);
721         } else
722             kdc_log(5, "Using e-types %d/%d", cetype, setype);
723     }
724     
725     {
726         char str[128];
727         unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
728         if(*str)
729             kdc_log(2, "Requested flags: %s", str);
730     }
731     
732
733     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
734        || (f.request_anonymous && !allow_anonymous)) {
735         ret = KRB5KDC_ERR_BADOPTION;
736         kdc_log(0, "Bad KDC options -- %s", client_name);
737         goto out;
738     }
739     
740     rep.pvno = 5;
741     rep.msg_type = krb_as_rep;
742     copy_Realm(&b->realm, &rep.crealm);
743     if (f.request_anonymous)
744         make_anonymous_principalname (&rep.cname);
745     else
746         copy_PrincipalName(b->cname, &rep.cname);
747     rep.ticket.tkt_vno = 5;
748     copy_Realm(&b->realm, &rep.ticket.realm);
749     copy_PrincipalName(b->sname, &rep.ticket.sname);
750
751     et.flags.initial = 1;
752     if(client->flags.forwardable && server->flags.forwardable)
753         et.flags.forwardable = f.forwardable;
754     else if (f.forwardable) {
755         ret = KRB5KDC_ERR_POLICY;
756         kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
757         goto out;
758     }
759     if(client->flags.proxiable && server->flags.proxiable)
760         et.flags.proxiable = f.proxiable;
761     else if (f.proxiable) {
762         ret = KRB5KDC_ERR_POLICY;
763         kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
764         goto out;
765     }
766     if(client->flags.postdate && server->flags.postdate)
767         et.flags.may_postdate = f.allow_postdate;
768     else if (f.allow_postdate){
769         ret = KRB5KDC_ERR_POLICY;
770         kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
771         goto out;
772     }
773
774     /* check for valid set of addresses */
775     if(!check_addresses(b->addresses, from_addr)) {
776         ret = KRB5KRB_AP_ERR_BADADDR;
777         kdc_log(0, "Bad address list requested -- %s", client_name);
778         goto out;
779     }
780
781     krb5_generate_random_keyblock(context, setype, &et.key);
782     copy_PrincipalName(&rep.cname, &et.cname);
783     copy_Realm(&b->realm, &et.crealm);
784     
785     {
786         time_t start;
787         time_t t;
788         
789         start = et.authtime = kdc_time;
790     
791         if(f.postdated && req->req_body.from){
792             ALLOC(et.starttime);
793             start = *et.starttime = *req->req_body.from;
794             et.flags.invalid = 1;
795             et.flags.postdated = 1; /* XXX ??? */
796         }
797         fix_time(&b->till);
798         t = *b->till;
799
800         /* be careful not overflowing */
801
802         if(client->max_life)
803             t = start + min(t - start, *client->max_life);
804         if(server->max_life)
805             t = start + min(t - start, *server->max_life);
806 #if 0
807         t = min(t, start + realm->max_life);
808 #endif
809         et.endtime = t;
810         if(f.renewable_ok && et.endtime < *b->till){
811             f.renewable = 1;
812             if(b->rtime == NULL){
813                 ALLOC(b->rtime);
814                 *b->rtime = 0;
815             }
816             if(*b->rtime < *b->till)
817                 *b->rtime = *b->till;
818         }
819         if(f.renewable && b->rtime){
820             t = *b->rtime;
821             if(t == 0)
822                 t = MAX_TIME;
823             if(client->max_renew)
824                 t = start + min(t - start, *client->max_renew);
825             if(server->max_renew)
826                 t = start + min(t - start, *server->max_renew);
827 #if 0
828             t = min(t, start + realm->max_renew);
829 #endif
830             ALLOC(et.renew_till);
831             *et.renew_till = t;
832             et.flags.renewable = 1;
833         }
834     }
835
836     if (f.request_anonymous)
837         et.flags.anonymous = 1;
838     
839     if(b->addresses){
840         ALLOC(et.caddr);
841         copy_HostAddresses(b->addresses, et.caddr);
842     }
843     
844     {
845         krb5_data empty_string;
846       
847         krb5_data_zero(&empty_string); 
848         et.transited.tr_type = DOMAIN_X500_COMPRESS;
849         et.transited.contents = empty_string;
850     }
851      
852     copy_EncryptionKey(&et.key, &ek.key);
853
854     /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
855      * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
856      * incapable of correctly decoding SEQUENCE OF's of zero length.
857      *
858      * To fix this, always send at least one no-op last_req
859      *
860      * If there's a pw_end or valid_end we will use that,
861      * otherwise just a dummy lr.
862      */
863     ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
864     ek.last_req.len = 0;
865     if (client->pw_end
866         && (kdc_warn_pwexpire == 0
867             || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
868         ek.last_req.val[ek.last_req.len].lr_type  = LR_PW_EXPTIME;
869         ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
870         ++ek.last_req.len;
871     }
872     if (client->valid_end) {
873         ek.last_req.val[ek.last_req.len].lr_type  = LR_ACCT_EXPTIME;
874         ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
875         ++ek.last_req.len;
876     }
877     if (ek.last_req.len == 0) {
878         ek.last_req.val[ek.last_req.len].lr_type  = LR_NONE;
879         ek.last_req.val[ek.last_req.len].lr_value = 0;
880         ++ek.last_req.len;
881     }
882     ek.nonce = b->nonce;
883     if (client->valid_end || client->pw_end) {
884         ALLOC(ek.key_expiration);
885         if (client->valid_end) {
886             if (client->pw_end)
887                 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
888             else
889                 *ek.key_expiration = *client->valid_end;
890         } else
891             *ek.key_expiration = *client->pw_end;
892     } else
893         ek.key_expiration = NULL;
894     ek.flags = et.flags;
895     ek.authtime = et.authtime;
896     if (et.starttime) {
897         ALLOC(ek.starttime);
898         *ek.starttime = *et.starttime;
899     }
900     ek.endtime = et.endtime;
901     if (et.renew_till) {
902         ALLOC(ek.renew_till);
903         *ek.renew_till = *et.renew_till;
904     }
905     copy_Realm(&rep.ticket.realm, &ek.srealm);
906     copy_PrincipalName(&rep.ticket.sname, &ek.sname);
907     if(et.caddr){
908         ALLOC(ek.caddr);
909         copy_HostAddresses(et.caddr, ek.caddr);
910     }
911
912     set_salt_padata (&rep.padata, ckey->salt);
913     ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
914                        client->kvno, &ckey->key, &e_text, reply);
915     free_EncTicketPart(&et);
916     free_EncKDCRepPart(&ek);
917     free_AS_REP(&rep);
918   out:
919     if(ret){
920         krb5_mk_error(context,
921                       ret,
922                       e_text,
923                       NULL,
924                       client_princ,
925                       server_princ,
926                       NULL,
927                       NULL,
928                       reply);
929         ret = 0;
930     }
931   out2:
932     krb5_free_principal(context, client_princ);
933     free(client_name);
934     krb5_free_principal(context, server_princ);
935     free(server_name);
936     if(client)
937         free_ent(client);
938     if(server)
939         free_ent(server);
940     return ret;
941 }
942
943
944 static krb5_error_code
945 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
946 {
947     KDCOptions f = b->kdc_options;
948         
949     if(f.validate){
950         if(!tgt->flags.invalid || tgt->starttime == NULL){
951             kdc_log(0, "Bad request to validate ticket");
952             return KRB5KDC_ERR_BADOPTION;
953         }
954         if(*tgt->starttime > kdc_time){
955             kdc_log(0, "Early request to validate ticket");
956             return KRB5KRB_AP_ERR_TKT_NYV;
957         }
958         /* XXX  tkt = tgt */
959         et->flags.invalid = 0;
960     }else if(tgt->flags.invalid){
961         kdc_log(0, "Ticket-granting ticket has INVALID flag set");
962         return KRB5KRB_AP_ERR_TKT_INVALID;
963     }
964
965     if(f.forwardable){
966         if(!tgt->flags.forwardable){
967             kdc_log(0, "Bad request for forwardable ticket");
968             return KRB5KDC_ERR_BADOPTION;
969         }
970         et->flags.forwardable = 1;
971     }
972     if(f.forwarded){
973         if(!tgt->flags.forwardable){
974             kdc_log(0, "Request to forward non-forwardable ticket");
975             return KRB5KDC_ERR_BADOPTION;
976         }
977         et->flags.forwarded = 1;
978         et->caddr = b->addresses;
979     }
980     if(tgt->flags.forwarded)
981         et->flags.forwarded = 1;
982         
983     if(f.proxiable){
984         if(!tgt->flags.proxiable){
985             kdc_log(0, "Bad request for proxiable ticket");
986             return KRB5KDC_ERR_BADOPTION;
987         }
988         et->flags.proxiable = 1;
989     }
990     if(f.proxy){
991         if(!tgt->flags.proxiable){
992             kdc_log(0, "Request to proxy non-proxiable ticket");
993             return KRB5KDC_ERR_BADOPTION;
994         }
995         et->flags.proxy = 1;
996         et->caddr = b->addresses;
997     }
998     if(tgt->flags.proxy)
999         et->flags.proxy = 1;
1000
1001     if(f.allow_postdate){
1002         if(!tgt->flags.may_postdate){
1003             kdc_log(0, "Bad request for post-datable ticket");
1004             return KRB5KDC_ERR_BADOPTION;
1005         }
1006         et->flags.may_postdate = 1;
1007     }
1008     if(f.postdated){
1009         if(!tgt->flags.may_postdate){
1010             kdc_log(0, "Bad request for postdated ticket");
1011             return KRB5KDC_ERR_BADOPTION;
1012         }
1013         if(b->from)
1014             *et->starttime = *b->from;
1015         et->flags.postdated = 1;
1016         et->flags.invalid = 1;
1017     }else if(b->from && *b->from > kdc_time + context->max_skew){
1018         kdc_log(0, "Ticket cannot be postdated");
1019         return KRB5KDC_ERR_CANNOT_POSTDATE;
1020     }
1021
1022     if(f.renewable){
1023         if(!tgt->flags.renewable){
1024             kdc_log(0, "Bad request for renewable ticket");
1025             return KRB5KDC_ERR_BADOPTION;
1026         }
1027         et->flags.renewable = 1;
1028         ALLOC(et->renew_till);
1029         fix_time(&b->rtime);
1030         *et->renew_till = *b->rtime;
1031     }
1032     if(f.renew){
1033         time_t old_life;
1034         if(!tgt->flags.renewable || tgt->renew_till == NULL){
1035             kdc_log(0, "Request to renew non-renewable ticket");
1036             return KRB5KDC_ERR_BADOPTION;
1037         }
1038         old_life = tgt->endtime;
1039         if(tgt->starttime)
1040             old_life -= *tgt->starttime;
1041         else
1042             old_life -= tgt->authtime;
1043         et->endtime = *et->starttime + old_life;
1044         if (et->renew_till != NULL)
1045             et->endtime = min(*et->renew_till, et->endtime);
1046     }       
1047     
1048     /* checks for excess flags */
1049     if(f.request_anonymous && !allow_anonymous){
1050         kdc_log(0, "Request for anonymous ticket");
1051         return KRB5KDC_ERR_BADOPTION;
1052     }
1053     return 0;
1054 }
1055
1056 static krb5_error_code
1057 fix_transited_encoding(TransitedEncoding *tr, 
1058                        const char *client_realm, 
1059                        const char *server_realm, 
1060                        const char *tgt_realm)
1061 {
1062     krb5_error_code ret = 0;
1063     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)){
1064         char **realms = NULL, **tmp;
1065         int num_realms = 0;
1066         int i;
1067         if(tr->tr_type && tr->contents.length != 0) {
1068             if(tr->tr_type != DOMAIN_X500_COMPRESS){
1069                 kdc_log(0, "Unknown transited type: %u", 
1070                         tr->tr_type);
1071                 return KRB5KDC_ERR_TRTYPE_NOSUPP;
1072             }
1073             ret = krb5_domain_x500_decode(context, 
1074                                           tr->contents,
1075                                           &realms, 
1076                                           &num_realms,
1077                                           client_realm,
1078                                           server_realm);
1079             if(ret){
1080                 krb5_warn(context, ret, "Decoding transited encoding");
1081                 return ret;
1082             }
1083         }
1084         if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
1085             ret = ERANGE;
1086             goto free_realms;
1087         }
1088         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1089         if(tmp == NULL){
1090             ret = ENOMEM;
1091             goto free_realms;
1092         }
1093         realms = tmp;
1094         realms[num_realms] = strdup(tgt_realm);
1095         if(realms[num_realms] == NULL){
1096             ret = ENOMEM;
1097             goto free_realms;
1098         }
1099         num_realms++;
1100         free_TransitedEncoding(tr);
1101         tr->tr_type = DOMAIN_X500_COMPRESS;
1102         ret = krb5_domain_x500_encode(realms, num_realms, &tr->contents);
1103         if(ret)
1104             krb5_warn(context, ret, "Encoding transited encoding");
1105     free_realms:
1106         for(i = 0; i < num_realms; i++)
1107             free(realms[i]);
1108         free(realms);
1109     }
1110     return ret;
1111 }
1112
1113
1114 static krb5_error_code
1115 tgs_make_reply(KDC_REQ_BODY *b, 
1116                EncTicketPart *tgt, 
1117                EncTicketPart *adtkt, 
1118                AuthorizationData *auth_data,
1119                hdb_entry *server, 
1120                hdb_entry *client, 
1121                krb5_principal client_principal, 
1122                hdb_entry *krbtgt,
1123                krb5_enctype cetype,
1124                const char **e_text,
1125                krb5_data *reply)
1126 {
1127     KDC_REP rep;
1128     EncKDCRepPart ek;
1129     EncTicketPart et;
1130     KDCOptions f = b->kdc_options;
1131     krb5_error_code ret;
1132     krb5_enctype etype;
1133     Key *skey;
1134     EncryptionKey *ekey;
1135     
1136     if(adtkt) {
1137         int i;
1138         krb5_keytype kt;
1139         ekey = &adtkt->key;
1140         for(i = 0; i < b->etype.len; i++){
1141             ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
1142             if(ret)
1143                 continue;
1144             if(adtkt->key.keytype == kt)
1145                 break;
1146         }
1147         if(i == b->etype.len)
1148             return KRB5KDC_ERR_ETYPE_NOSUPP;
1149         etype = b->etype.val[i];
1150     }else{
1151         ret = find_keys(NULL, server, NULL, NULL, &skey, &etype, 
1152                         b->etype.val, b->etype.len);
1153         if(ret) {
1154             kdc_log(0, "Server has no support for etypes");
1155             return ret;
1156         }
1157         ekey = &skey->key;
1158     }
1159     
1160     memset(&rep, 0, sizeof(rep));
1161     memset(&et, 0, sizeof(et));
1162     memset(&ek, 0, sizeof(ek));
1163     
1164     rep.pvno = 5;
1165     rep.msg_type = krb_tgs_rep;
1166
1167     et.authtime = tgt->authtime;
1168     fix_time(&b->till);
1169     et.endtime = min(tgt->endtime, *b->till);
1170     ALLOC(et.starttime);
1171     *et.starttime = kdc_time;
1172     
1173     ret = check_tgs_flags(b, tgt, &et);
1174     if(ret)
1175         return ret;
1176
1177     copy_TransitedEncoding(&tgt->transited, &et.transited);
1178     ret = fix_transited_encoding(&et.transited,
1179                                  *krb5_princ_realm(context, client_principal),
1180                                  *krb5_princ_realm(context, server->principal),
1181                                  *krb5_princ_realm(context, krbtgt->principal));
1182     if(ret){
1183         free_TransitedEncoding(&et.transited);
1184         return ret;
1185     }
1186
1187
1188     copy_Realm(krb5_princ_realm(context, server->principal), 
1189                &rep.ticket.realm);
1190     krb5_principal2principalname(&rep.ticket.sname, server->principal);
1191     copy_Realm(&tgt->crealm, &rep.crealm);
1192     if (f.request_anonymous)
1193         make_anonymous_principalname (&tgt->cname);
1194     else
1195         copy_PrincipalName(&tgt->cname, &rep.cname);
1196     rep.ticket.tkt_vno = 5;
1197
1198     ek.caddr = et.caddr;
1199     if(et.caddr == NULL)
1200         et.caddr = tgt->caddr;
1201
1202     {
1203         time_t life;
1204         life = et.endtime - *et.starttime;
1205         if(client && client->max_life)
1206             life = min(life, *client->max_life);
1207         if(server->max_life)
1208             life = min(life, *server->max_life);
1209         et.endtime = *et.starttime + life;
1210     }
1211     if(f.renewable_ok && tgt->flags.renewable && 
1212        et.renew_till == NULL && et.endtime < *b->till){
1213         et.flags.renewable = 1;
1214         ALLOC(et.renew_till);
1215         *et.renew_till = *b->till;
1216     }
1217     if(et.renew_till){
1218         time_t renew;
1219         renew = *et.renew_till - et.authtime;
1220         if(client && client->max_renew)
1221             renew = min(renew, *client->max_renew);
1222         if(server->max_renew)
1223             renew = min(renew, *server->max_renew);
1224         *et.renew_till = et.authtime + renew;
1225     }
1226             
1227     if(et.renew_till){
1228         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
1229         *et.starttime = min(*et.starttime, *et.renew_till);
1230         et.endtime = min(et.endtime, *et.renew_till);
1231     }
1232     
1233     *et.starttime = min(*et.starttime, et.endtime);
1234
1235     if(*et.starttime == et.endtime){
1236         ret = KRB5KDC_ERR_NEVER_VALID;
1237         goto out;
1238     }
1239     if(et.renew_till && et.endtime == *et.renew_till){
1240         free(et.renew_till);
1241         et.renew_till = NULL;
1242         et.flags.renewable = 0;
1243     }
1244     
1245     et.flags.pre_authent = tgt->flags.pre_authent;
1246     et.flags.hw_authent  = tgt->flags.hw_authent;
1247     et.flags.anonymous   = tgt->flags.anonymous;
1248             
1249     /* XXX Check enc-authorization-data */
1250     et.authorization_data = auth_data;
1251
1252     krb5_generate_random_keyblock(context, etype, &et.key);
1253     et.crealm = tgt->crealm;
1254     et.cname = tgt->cname;
1255             
1256     ek.key = et.key;
1257     /* MIT must have at least one last_req */
1258     ek.last_req.len = 1;
1259     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1260     ek.nonce = b->nonce;
1261     ek.flags = et.flags;
1262     ek.authtime = et.authtime;
1263     ek.starttime = et.starttime;
1264     ek.endtime = et.endtime;
1265     ek.renew_till = et.renew_till;
1266     ek.srealm = rep.ticket.realm;
1267     ek.sname = rep.ticket.sname;
1268             
1269     /* It is somewhat unclear where the etype in the following
1270        encryption should come from. What we have is a session
1271        key in the passed tgt, and a list of preferred etypes
1272        *for the new ticket*. Should we pick the best possible
1273        etype, given the keytype in the tgt, or should we look
1274        at the etype list here as well?  What if the tgt
1275        session key is DES3 and we want a ticket with a (say)
1276        CAST session key. Should the DES3 etype be added to the
1277        etype list, even if we don't want a session key with
1278        DES3? */
1279     ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
1280                        0, &tgt->key, e_text, reply);
1281 out:
1282     free_TGS_REP(&rep);
1283     free_TransitedEncoding(&et.transited);
1284     if(et.starttime)
1285         free(et.starttime);
1286     if(et.renew_till)
1287         free(et.renew_till);
1288     free_LastReq(&ek.last_req);
1289     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1290     free_EncryptionKey(&et.key);
1291     return ret;
1292 }
1293
1294 static krb5_error_code
1295 tgs_check_authenticator(krb5_auth_context ac,
1296                         KDC_REQ_BODY *b, 
1297                         const char **e_text,
1298                         krb5_keyblock *key)
1299 {
1300     krb5_authenticator auth;
1301     size_t len;
1302     unsigned char *buf;
1303     size_t buf_size;
1304     krb5_error_code ret;
1305     krb5_crypto crypto;
1306     
1307     krb5_auth_con_getauthenticator(context, ac, &auth);
1308     if(auth->cksum == NULL){
1309         kdc_log(0, "No authenticator in request");
1310         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1311         goto out;
1312     }
1313     /*
1314      * according to RFC1510 it doesn't need to be keyed,
1315      * but according to the latest draft it needs to.
1316      */
1317     if (
1318 #if 0
1319 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1320         ||
1321 #endif
1322  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1323         kdc_log(0, "Bad checksum type in authenticator: %d", 
1324                 auth->cksum->cksumtype);
1325         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1326         goto out;
1327     }
1328                 
1329     /* XXX should not re-encode this */
1330     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1331     if(ret){
1332         kdc_log(0, "Failed to encode KDC-REQ-BODY: %s", 
1333                 krb5_get_err_text(context, ret));
1334         goto out;
1335     }
1336     if(buf_size != len) {
1337         free(buf);
1338         kdc_log(0, "Internal error in ASN.1 encoder");
1339         *e_text = "KDC internal error";
1340         ret = KRB5KRB_ERR_GENERIC;
1341         goto out;
1342     }
1343     ret = krb5_crypto_init(context, key, 0, &crypto);
1344     if (ret) {
1345         free(buf);
1346         kdc_log(0, "krb5_crypto_init failed: %s",
1347                 krb5_get_err_text(context, ret));
1348         goto out;
1349     }
1350     ret = krb5_verify_checksum(context,
1351                                crypto,
1352                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
1353                                buf, 
1354                                len,
1355                                auth->cksum);
1356     free(buf);
1357     krb5_crypto_destroy(context, crypto);
1358     if(ret){
1359         kdc_log(0, "Failed to verify checksum: %s", 
1360                 krb5_get_err_text(context, ret));
1361     }
1362 out:
1363     free_Authenticator(auth);
1364     free(auth);
1365     return ret;
1366 }
1367
1368 /*
1369  * return the realm of a krbtgt-ticket or NULL
1370  */
1371
1372 static Realm 
1373 get_krbtgt_realm(const PrincipalName *p)
1374 {
1375     if(p->name_string.len == 2
1376        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
1377         return p->name_string.val[1];
1378     else
1379         return NULL;
1380 }
1381
1382 static Realm
1383 find_rpath(Realm r)
1384 {
1385     const char *new_realm = krb5_config_get_string(context,
1386                                                    NULL,
1387                                                    "libdefaults", 
1388                                                    "capath", 
1389                                                    r, 
1390                                                    NULL);
1391     return (Realm)new_realm;
1392 }
1393             
1394
1395 static krb5_boolean
1396 need_referral(krb5_principal server, krb5_realm **realms)
1397 {
1398     if(server->name.name_type != KRB5_NT_SRV_INST ||
1399        server->name.name_string.len != 2)
1400         return FALSE;
1401  
1402     return krb5_get_host_realm_int(context, server->name.name_string.val[1],
1403                                    FALSE, realms) == 0;
1404 }
1405
1406 static krb5_error_code
1407 tgs_rep2(KDC_REQ_BODY *b,
1408          PA_DATA *tgs_req,
1409          krb5_data *reply,
1410          const char *from,
1411          const struct sockaddr *from_addr,
1412          time_t **csec,
1413          int **cusec)
1414 {
1415     krb5_ap_req ap_req;
1416     krb5_error_code ret;
1417     krb5_principal princ;
1418     krb5_auth_context ac = NULL;
1419     krb5_ticket *ticket = NULL;
1420     krb5_flags ap_req_options;
1421     krb5_flags verify_ap_req_flags;
1422     const char *e_text = NULL;
1423     krb5_crypto crypto;
1424
1425     hdb_entry *krbtgt = NULL;
1426     EncTicketPart *tgt;
1427     Key *tkey;
1428     krb5_enctype cetype;
1429     krb5_principal cp = NULL;
1430     krb5_principal sp = NULL;
1431     AuthorizationData *auth_data = NULL;
1432
1433     *csec  = NULL;
1434     *cusec = NULL;
1435
1436     memset(&ap_req, 0, sizeof(ap_req));
1437     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1438     if(ret){
1439         kdc_log(0, "Failed to decode AP-REQ: %s", 
1440                 krb5_get_err_text(context, ret));
1441         goto out2;
1442     }
1443     
1444     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1445         /* XXX check for ticket.sname == req.sname */
1446         kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1447         ret = KRB5KDC_ERR_POLICY; /* ? */
1448         goto out2;
1449     }
1450     
1451     principalname2krb5_principal(&princ,
1452                                  ap_req.ticket.sname,
1453                                  ap_req.ticket.realm);
1454     
1455     ret = db_fetch(princ, &krbtgt);
1456
1457     if(ret) {
1458         char *p;
1459         krb5_unparse_name(context, princ, &p);
1460         kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
1461                 p, krb5_get_err_text(context, ret));
1462         free(p);
1463         ret = KRB5KRB_AP_ERR_NOT_US;
1464         goto out2;
1465     }
1466     
1467     if(ap_req.ticket.enc_part.kvno && 
1468        *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
1469         char *p;
1470
1471         krb5_unparse_name (context, princ, &p);
1472         kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)", 
1473                 *ap_req.ticket.enc_part.kvno,
1474                 krbtgt->kvno,
1475                 p);
1476         free (p);
1477         ret = KRB5KRB_AP_ERR_BADKEYVER;
1478         goto out2;
1479     }
1480
1481     ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
1482     if(ret){
1483         char *str;
1484         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1485         kdc_log(0, "No server key found for %s", str);
1486         free(str);
1487         ret = KRB5KRB_AP_ERR_BADKEYVER;
1488         goto out2;
1489     }
1490     
1491     if (b->kdc_options.validate)
1492         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1493     else
1494         verify_ap_req_flags = 0;
1495
1496     ret = krb5_verify_ap_req2(context,
1497                               &ac,
1498                               &ap_req,
1499                               princ,
1500                               &tkey->key,
1501                               verify_ap_req_flags,
1502                               &ap_req_options,
1503                               &ticket,
1504                               KRB5_KU_TGS_REQ_AUTH);
1505                              
1506     krb5_free_principal(context, princ);
1507     if(ret) {
1508         kdc_log(0, "Failed to verify AP-REQ: %s", 
1509                 krb5_get_err_text(context, ret));
1510         goto out2;
1511     }
1512
1513     {
1514         krb5_authenticator auth;
1515
1516         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1517         if (ret == 0) {
1518             *csec   = malloc(sizeof(**csec));
1519             if (*csec == NULL) {
1520                 krb5_free_authenticator(context, &auth);
1521                 kdc_log(0, "malloc failed");
1522                 goto out2;
1523             }
1524             **csec  = auth->ctime;
1525             *cusec  = malloc(sizeof(**cusec));
1526             if (*cusec == NULL) {
1527                 krb5_free_authenticator(context, &auth);
1528                 kdc_log(0, "malloc failed");
1529                 goto out2;
1530             }
1531             **csec  = auth->cusec;
1532             krb5_free_authenticator(context, &auth);
1533         }
1534     }
1535
1536     cetype = ap_req.authenticator.etype;
1537
1538     tgt = &ticket->ticket;
1539
1540     ret = tgs_check_authenticator(ac, b, &e_text, &tgt->key);
1541
1542     if (b->enc_authorization_data) {
1543         krb5_keyblock *subkey;
1544         krb5_data ad;
1545         ret = krb5_auth_con_getremotesubkey(context,
1546                                             ac,
1547                                             &subkey);
1548         if(ret){
1549             krb5_auth_con_free(context, ac);
1550             kdc_log(0, "Failed to get remote subkey: %s", 
1551                     krb5_get_err_text(context, ret));
1552             goto out2;
1553         }
1554         if(subkey == NULL){
1555             ret = krb5_auth_con_getkey(context, ac, &subkey);
1556             if(ret) {
1557                 krb5_auth_con_free(context, ac);
1558                 kdc_log(0, "Failed to get session key: %s", 
1559                         krb5_get_err_text(context, ret));
1560                 goto out2;
1561             }
1562         }
1563         if(subkey == NULL){
1564             krb5_auth_con_free(context, ac);
1565             kdc_log(0, "Failed to get key for enc-authorization-data");
1566             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1567             goto out2;
1568         }
1569         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1570         if (ret) {
1571             krb5_auth_con_free(context, ac);
1572             kdc_log(0, "krb5_crypto_init failed: %s",
1573                     krb5_get_err_text(context, ret));
1574             goto out2;
1575         }
1576         ret = krb5_decrypt_EncryptedData (context,
1577                                           crypto,
1578                                           KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1579                                           b->enc_authorization_data,
1580                                           &ad);
1581         krb5_crypto_destroy(context, crypto);
1582         if(ret){
1583             krb5_auth_con_free(context, ac);
1584             kdc_log(0, "Failed to decrypt enc-authorization-data");
1585             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1586             goto out2;
1587         }
1588         krb5_free_keyblock(context, subkey);
1589         ALLOC(auth_data);
1590         ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1591         if(ret){
1592             krb5_auth_con_free(context, ac);
1593             free(auth_data);
1594             auth_data = NULL;
1595             kdc_log(0, "Failed to decode authorization data");
1596             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1597             goto out2;
1598         }
1599     }
1600
1601     krb5_auth_con_free(context, ac);
1602
1603     if(ret){
1604         kdc_log(0, "Failed to verify authenticator: %s", 
1605                 krb5_get_err_text(context, ret));
1606         goto out2;
1607     }
1608     
1609     {
1610         PrincipalName *s;
1611         Realm r;
1612         char *spn = NULL, *cpn = NULL;
1613         hdb_entry *server = NULL, *client = NULL;
1614         int loop = 0;
1615         EncTicketPart adtkt;
1616         char opt_str[128];
1617
1618         s = b->sname;
1619         r = b->realm;
1620         if(b->kdc_options.enc_tkt_in_skey){
1621             Ticket *t;
1622             hdb_entry *uu;
1623             krb5_principal p;
1624             Key *tkey;
1625             
1626             if(b->additional_tickets == NULL || 
1627                b->additional_tickets->len == 0){
1628                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1629                 kdc_log(0, "No second ticket present in request");
1630                 goto out;
1631             }
1632             t = &b->additional_tickets->val[0];
1633             if(!get_krbtgt_realm(&t->sname)){
1634                 kdc_log(0, "Additional ticket is not a ticket-granting ticket");
1635                 ret = KRB5KDC_ERR_POLICY;
1636                 goto out2;
1637             }
1638             principalname2krb5_principal(&p, t->sname, t->realm);
1639             ret = db_fetch(p, &uu);
1640             krb5_free_principal(context, p);
1641             if(ret){
1642                 if (ret == HDB_ERR_NOENTRY)
1643                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1644                 goto out;
1645             }
1646             ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
1647             if(ret){
1648                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1649                 goto out;
1650             }
1651             ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0);
1652
1653             if(ret)
1654                 goto out;
1655             s = &adtkt.cname;
1656             r = adtkt.crealm;
1657         }
1658
1659         principalname2krb5_principal(&sp, *s, r);
1660         krb5_unparse_name(context, sp, &spn);   
1661         principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1662         krb5_unparse_name(context, cp, &cpn);
1663         unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
1664                        opt_str, sizeof(opt_str));
1665         if(*opt_str)
1666             kdc_log(0, "TGS-REQ %s from %s for %s [%s]", 
1667                     cpn, from, spn, opt_str);
1668         else
1669             kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1670     server_lookup:
1671         ret = db_fetch(sp, &server);
1672
1673         if(ret){
1674             Realm req_rlm, new_rlm;
1675             krb5_realm *realms;
1676
1677             if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1678                 if(loop++ < 2) {
1679                     new_rlm = find_rpath(req_rlm);
1680                     if(new_rlm) {
1681                         kdc_log(5, "krbtgt for realm %s not found, trying %s", 
1682                                 req_rlm, new_rlm);
1683                         krb5_free_principal(context, sp);
1684                         free(spn);
1685                         krb5_make_principal(context, &sp, r, 
1686                                             KRB5_TGS_NAME, new_rlm, NULL);
1687                         krb5_unparse_name(context, sp, &spn);   
1688                         goto server_lookup;
1689                     }
1690                 }
1691             } else if(need_referral(sp, &realms)) {
1692                 if (strcmp(realms[0], sp->realm) != 0) {
1693                     kdc_log(5, "returning a referral to realm %s for "
1694                             "server %s that was not found",
1695                             realms[0], spn);
1696                     krb5_free_principal(context, sp);
1697                     free(spn);
1698                     krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1699                                         realms[0], NULL);
1700                     krb5_unparse_name(context, sp, &spn);
1701                     krb5_free_host_realm(context, realms);
1702                     goto server_lookup;
1703                 }
1704                 krb5_free_host_realm(context, realms);
1705             }
1706             kdc_log(0, "Server not found in database: %s: %s", spn,
1707                     krb5_get_err_text(context, ret));
1708             if (ret == HDB_ERR_NOENTRY)
1709                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1710             goto out;
1711         }
1712
1713         ret = db_fetch(cp, &client);
1714         if(ret)
1715             kdc_log(1, "Client not found in database: %s: %s",
1716                     cpn, krb5_get_err_text(context, ret));
1717 #if 0
1718         /* XXX check client only if same realm as krbtgt-instance */
1719         if(ret){
1720             kdc_log(0, "Client not found in database: %s: %s",
1721                     cpn, krb5_get_err_text(context, ret));
1722             if (ret == HDB_ERR_NOENTRY)
1723                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1724             goto out;
1725         }
1726 #endif
1727
1728         ret = check_flags(client, cpn, server, spn, FALSE);
1729         if(ret)
1730             goto out;
1731
1732         if((b->kdc_options.validate || b->kdc_options.renew) && 
1733            !krb5_principal_compare(context, 
1734                                    krbtgt->principal,
1735                                    server->principal)){
1736             kdc_log(0, "Inconsistent request.");
1737             ret = KRB5KDC_ERR_SERVER_NOMATCH;
1738             goto out;
1739         }
1740
1741         /* check for valid set of addresses */
1742         if(!check_addresses(tgt->caddr, from_addr)) {
1743             ret = KRB5KRB_AP_ERR_BADADDR;
1744             kdc_log(0, "Request from wrong address");
1745             goto out;
1746         }
1747         
1748         ret = tgs_make_reply(b, 
1749                              tgt, 
1750                              b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
1751                              auth_data,
1752                              server, 
1753                              client, 
1754                              cp, 
1755                              krbtgt, 
1756                              cetype, 
1757                              &e_text,
1758                              reply);
1759         
1760     out:
1761         free(spn);
1762         free(cpn);
1763             
1764         if(server)
1765             free_ent(server);
1766         if(client)
1767             free_ent(client);
1768     }
1769 out2:
1770     if(ret) {
1771         krb5_mk_error(context,
1772                       ret,
1773                       e_text,
1774                       NULL,
1775                       cp,
1776                       sp,
1777                       NULL,
1778                       NULL,
1779                       reply);
1780         free(*csec);
1781         free(*cusec);
1782         *csec  = NULL;
1783         *cusec = NULL;
1784     }
1785     krb5_free_principal(context, cp);
1786     krb5_free_principal(context, sp);
1787     if (ticket) {
1788         krb5_free_ticket(context, ticket);
1789         free(ticket);
1790     }
1791     free_AP_REQ(&ap_req);
1792     if(auth_data){
1793         free_AuthorizationData(auth_data);
1794         free(auth_data);
1795     }
1796
1797     if(krbtgt)
1798         free_ent(krbtgt);
1799
1800     return ret;
1801 }
1802
1803
1804 krb5_error_code
1805 tgs_rep(KDC_REQ *req, 
1806         krb5_data *data,
1807         const char *from,
1808         struct sockaddr *from_addr)
1809 {
1810     krb5_error_code ret;
1811     int i = 0;
1812     PA_DATA *tgs_req = NULL;
1813     time_t *csec = NULL;
1814     int *cusec = NULL;
1815
1816     if(req->padata == NULL){
1817         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1818         kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1819         goto out;
1820     }
1821     
1822     tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1823
1824     if(tgs_req == NULL){
1825         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1826         
1827         kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1828         goto out;
1829     }
1830     ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr,
1831                    &csec, &cusec);
1832 out:
1833     if(ret && data->data == NULL){
1834         krb5_mk_error(context,
1835                       ret,
1836                       NULL,
1837                       NULL,
1838                       NULL,
1839                       NULL,
1840                       csec,
1841                       cusec,
1842                       data);
1843     }
1844     free(csec);
1845     free(cusec);
1846     return 0;
1847 }