]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/heimdal/kdc/kerberos5.c
Do not include lib/kdfs in future imports.
[FreeBSD/FreeBSD.git] / crypto / heimdal / 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.3 2003/12/14 19:43:04 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 < 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 = NULL, server_princ = NULL;
500     char *client_name = NULL, *server_name = NULL;
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         ret = KRB5KRB_ERR_GENERIC;
510         e_text = "No server in request";
511     } else{
512         principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
513         krb5_unparse_name(context, server_princ, &server_name);
514     }
515     if (ret) {
516         kdc_log(0, "AS-REQ malformed server name from %s", from);
517         goto out;
518     }
519     
520     if(b->cname == NULL){
521         ret = KRB5KRB_ERR_GENERIC;
522         e_text = "No client in request";
523     } else {
524         principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
525         krb5_unparse_name(context, client_princ, &client_name);
526     }
527     if (ret) {
528         kdc_log(0, "AS-REQ malformed client name from %s", from);
529         goto out;
530     }
531
532     kdc_log(0, "AS-REQ %s from %s for %s", client_name, from, server_name);
533
534     ret = db_fetch(client_princ, &client);
535     if(ret){
536         kdc_log(0, "UNKNOWN -- %s: %s", client_name,
537                 krb5_get_err_text(context, ret));
538         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
539         goto out;
540     }
541
542     ret = db_fetch(server_princ, &server);
543     if(ret){
544         kdc_log(0, "UNKNOWN -- %s: %s", server_name,
545                 krb5_get_err_text(context, ret));
546         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
547         goto out;
548     }
549
550     ret = check_flags(client, client_name, server, server_name, TRUE);
551     if(ret)
552         goto out;
553
554     memset(&et, 0, sizeof(et));
555     memset(&ek, 0, sizeof(ek));
556
557     if(req->padata){
558         int i = 0;
559         PA_DATA *pa;
560         int found_pa = 0;
561         kdc_log(5, "Looking for pa-data -- %s", client_name);
562         while((pa = find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){
563             krb5_data ts_data;
564             PA_ENC_TS_ENC p;
565             time_t patime;
566             size_t len;
567             EncryptedData enc_data;
568             Key *pa_key;
569             
570             found_pa = 1;
571             
572             ret = decode_EncryptedData(pa->padata_value.data,
573                                        pa->padata_value.length,
574                                        &enc_data,
575                                        &len);
576             if (ret) {
577                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
578                 kdc_log(5, "Failed to decode PA-DATA -- %s", 
579                         client_name);
580                 goto out;
581             }
582             
583             ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key);
584             if(ret){
585                 char *estr;
586                 e_text = "No key matches pa-data";
587                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
588                 if(krb5_enctype_to_string(context, enc_data.etype, &estr))
589                     estr = NULL;
590                 if(estr == NULL)
591                     kdc_log(5, "No client key matching pa-data (%d) -- %s", 
592                             enc_data.etype, client_name);
593                 else
594                     kdc_log(5, "No client key matching pa-data (%s) -- %s", 
595                             estr, client_name);
596                 free(estr);
597                     
598                 free_EncryptedData(&enc_data);
599                 continue;
600             }
601
602           try_next_key:
603             ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto);
604             if (ret) {
605                 kdc_log(0, "krb5_crypto_init failed: %s",
606                         krb5_get_err_text(context, ret));
607                 free_EncryptedData(&enc_data);
608                 continue;
609             }
610
611             ret = krb5_decrypt_EncryptedData (context,
612                                               crypto,
613                                               KRB5_KU_PA_ENC_TIMESTAMP,
614                                               &enc_data,
615                                               &ts_data);
616             krb5_crypto_destroy(context, crypto);
617             if(ret){
618                 if(hdb_next_enctype2key(context, client, 
619                                         enc_data.etype, &pa_key) == 0)
620                     goto try_next_key;
621                 free_EncryptedData(&enc_data);
622                 e_text = "Failed to decrypt PA-DATA";
623                 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
624                          client_name);
625                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
626                 continue;
627             }
628             free_EncryptedData(&enc_data);
629             ret = decode_PA_ENC_TS_ENC(ts_data.data,
630                                        ts_data.length,
631                                        &p,
632                                        &len);
633             krb5_data_free(&ts_data);
634             if(ret){
635                 e_text = "Failed to decode PA-ENC-TS-ENC";
636                 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
637                 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
638                          client_name);
639                 continue;
640             }
641             patime = p.patimestamp;
642             free_PA_ENC_TS_ENC(&p);
643             if (abs(kdc_time - p.patimestamp) > context->max_skew) {
644                 ret = KRB5KDC_ERR_PREAUTH_FAILED;
645                 e_text = "Too large time skew";
646                 kdc_log(0, "Too large time skew -- %s", client_name);
647                 goto out;
648             }
649             et.flags.pre_authent = 1;
650             kdc_log(2, "Pre-authentication succeded -- %s", client_name);
651             break;
652         }
653         if(found_pa == 0 && require_preauth)
654             goto use_pa;
655         /* We come here if we found a pa-enc-timestamp, but if there
656            was some problem with it, other than too large skew */
657         if(found_pa && et.flags.pre_authent == 0){
658             kdc_log(0, "%s -- %s", e_text, client_name);
659             e_text = NULL;
660             goto out;
661         }
662     }else if (require_preauth
663               || client->flags.require_preauth
664               || server->flags.require_preauth) {
665         METHOD_DATA method_data;
666         PA_DATA *pa;
667         unsigned char *buf;
668         size_t len;
669         krb5_data foo_data;
670
671       use_pa: 
672         method_data.len = 0;
673         method_data.val = NULL;
674
675         ret = realloc_method_data(&method_data);
676         pa = &method_data.val[method_data.len-1];
677         pa->padata_type         = KRB5_PADATA_ENC_TIMESTAMP;
678         pa->padata_value.length = 0;
679         pa->padata_value.data   = NULL;
680
681         ret = get_pa_etype_info(&method_data, client, 
682                                 b->etype.val, b->etype.len); /* XXX check ret */
683         
684         ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret);
685         free_METHOD_DATA(&method_data);
686         foo_data.data   = buf;
687         foo_data.length = len;
688         
689         ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
690         krb5_mk_error(context,
691                       ret,
692                       "Need to use PA-ENC-TIMESTAMP",
693                       &foo_data,
694                       client_princ,
695                       server_princ,
696                       NULL,
697                       NULL,
698                       reply);
699         free(buf);
700         kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
701         ret = 0;
702         goto out2;
703     }
704     
705     ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
706                     b->etype.val, b->etype.len);
707     if(ret) {
708         kdc_log(0, "Server/client has no support for etypes");
709         goto out;
710     }
711         
712     {
713         char *cet;
714         char *set;
715
716         ret = krb5_enctype_to_string(context, cetype, &cet);
717         if(ret == 0) {
718             ret = krb5_enctype_to_string(context, setype, &set);
719             if (ret == 0) {
720                 kdc_log(5, "Using %s/%s", cet, set);
721                 free(set);
722             }
723             free(cet);
724         }
725         if (ret != 0)
726             kdc_log(5, "Using e-types %d/%d", cetype, setype);
727     }
728     
729     {
730         char str[128];
731         unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
732         if(*str)
733             kdc_log(2, "Requested flags: %s", str);
734     }
735     
736
737     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
738        || (f.request_anonymous && !allow_anonymous)) {
739         ret = KRB5KDC_ERR_BADOPTION;
740         kdc_log(0, "Bad KDC options -- %s", client_name);
741         goto out;
742     }
743     
744     rep.pvno = 5;
745     rep.msg_type = krb_as_rep;
746     copy_Realm(&b->realm, &rep.crealm);
747     if (f.request_anonymous)
748         make_anonymous_principalname (&rep.cname);
749     else
750         copy_PrincipalName(b->cname, &rep.cname);
751     rep.ticket.tkt_vno = 5;
752     copy_Realm(&b->realm, &rep.ticket.realm);
753     copy_PrincipalName(b->sname, &rep.ticket.sname);
754
755     et.flags.initial = 1;
756     if(client->flags.forwardable && server->flags.forwardable)
757         et.flags.forwardable = f.forwardable;
758     else if (f.forwardable) {
759         ret = KRB5KDC_ERR_POLICY;
760         kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
761         goto out;
762     }
763     if(client->flags.proxiable && server->flags.proxiable)
764         et.flags.proxiable = f.proxiable;
765     else if (f.proxiable) {
766         ret = KRB5KDC_ERR_POLICY;
767         kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
768         goto out;
769     }
770     if(client->flags.postdate && server->flags.postdate)
771         et.flags.may_postdate = f.allow_postdate;
772     else if (f.allow_postdate){
773         ret = KRB5KDC_ERR_POLICY;
774         kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
775         goto out;
776     }
777
778     /* check for valid set of addresses */
779     if(!check_addresses(b->addresses, from_addr)) {
780         ret = KRB5KRB_AP_ERR_BADADDR;
781         kdc_log(0, "Bad address list requested -- %s", client_name);
782         goto out;
783     }
784
785     krb5_generate_random_keyblock(context, setype, &et.key);
786     copy_PrincipalName(&rep.cname, &et.cname);
787     copy_Realm(&b->realm, &et.crealm);
788     
789     {
790         time_t start;
791         time_t t;
792         
793         start = et.authtime = kdc_time;
794     
795         if(f.postdated && req->req_body.from){
796             ALLOC(et.starttime);
797             start = *et.starttime = *req->req_body.from;
798             et.flags.invalid = 1;
799             et.flags.postdated = 1; /* XXX ??? */
800         }
801         fix_time(&b->till);
802         t = *b->till;
803
804         /* be careful not overflowing */
805
806         if(client->max_life)
807             t = start + min(t - start, *client->max_life);
808         if(server->max_life)
809             t = start + min(t - start, *server->max_life);
810 #if 0
811         t = min(t, start + realm->max_life);
812 #endif
813         et.endtime = t;
814         if(f.renewable_ok && et.endtime < *b->till){
815             f.renewable = 1;
816             if(b->rtime == NULL){
817                 ALLOC(b->rtime);
818                 *b->rtime = 0;
819             }
820             if(*b->rtime < *b->till)
821                 *b->rtime = *b->till;
822         }
823         if(f.renewable && b->rtime){
824             t = *b->rtime;
825             if(t == 0)
826                 t = MAX_TIME;
827             if(client->max_renew)
828                 t = start + min(t - start, *client->max_renew);
829             if(server->max_renew)
830                 t = start + min(t - start, *server->max_renew);
831 #if 0
832             t = min(t, start + realm->max_renew);
833 #endif
834             ALLOC(et.renew_till);
835             *et.renew_till = t;
836             et.flags.renewable = 1;
837         }
838     }
839
840     if (f.request_anonymous)
841         et.flags.anonymous = 1;
842     
843     if(b->addresses){
844         ALLOC(et.caddr);
845         copy_HostAddresses(b->addresses, et.caddr);
846     }
847     
848     et.transited.tr_type = DOMAIN_X500_COMPRESS;
849     krb5_data_zero(&et.transited.contents); 
850      
851     copy_EncryptionKey(&et.key, &ek.key);
852
853     /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
854      * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
855      * incapable of correctly decoding SEQUENCE OF's of zero length.
856      *
857      * To fix this, always send at least one no-op last_req
858      *
859      * If there's a pw_end or valid_end we will use that,
860      * otherwise just a dummy lr.
861      */
862     ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
863     ek.last_req.len = 0;
864     if (client->pw_end
865         && (kdc_warn_pwexpire == 0
866             || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
867         ek.last_req.val[ek.last_req.len].lr_type  = LR_PW_EXPTIME;
868         ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
869         ++ek.last_req.len;
870     }
871     if (client->valid_end) {
872         ek.last_req.val[ek.last_req.len].lr_type  = LR_ACCT_EXPTIME;
873         ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
874         ++ek.last_req.len;
875     }
876     if (ek.last_req.len == 0) {
877         ek.last_req.val[ek.last_req.len].lr_type  = LR_NONE;
878         ek.last_req.val[ek.last_req.len].lr_value = 0;
879         ++ek.last_req.len;
880     }
881     ek.nonce = b->nonce;
882     if (client->valid_end || client->pw_end) {
883         ALLOC(ek.key_expiration);
884         if (client->valid_end) {
885             if (client->pw_end)
886                 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
887             else
888                 *ek.key_expiration = *client->valid_end;
889         } else
890             *ek.key_expiration = *client->pw_end;
891     } else
892         ek.key_expiration = NULL;
893     ek.flags = et.flags;
894     ek.authtime = et.authtime;
895     if (et.starttime) {
896         ALLOC(ek.starttime);
897         *ek.starttime = *et.starttime;
898     }
899     ek.endtime = et.endtime;
900     if (et.renew_till) {
901         ALLOC(ek.renew_till);
902         *ek.renew_till = *et.renew_till;
903     }
904     copy_Realm(&rep.ticket.realm, &ek.srealm);
905     copy_PrincipalName(&rep.ticket.sname, &ek.sname);
906     if(et.caddr){
907         ALLOC(ek.caddr);
908         copy_HostAddresses(et.caddr, ek.caddr);
909     }
910
911     set_salt_padata (&rep.padata, ckey->salt);
912     ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
913                        client->kvno, &ckey->key, &e_text, reply);
914     free_EncTicketPart(&et);
915     free_EncKDCRepPart(&ek);
916   out:
917     free_AS_REP(&rep);
918     if(ret){
919         krb5_mk_error(context,
920                       ret,
921                       e_text,
922                       NULL,
923                       client_princ,
924                       server_princ,
925                       NULL,
926                       NULL,
927                       reply);
928         ret = 0;
929     }
930   out2:
931     if (client_princ)
932         krb5_free_principal(context, client_princ);
933     free(client_name);
934     if (server_princ)
935         krb5_free_principal(context, server_princ);
936     free(server_name);
937     if(client)
938         free_ent(client);
939     if(server)
940         free_ent(server);
941     return ret;
942 }
943
944
945 static krb5_error_code
946 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
947 {
948     KDCOptions f = b->kdc_options;
949         
950     if(f.validate){
951         if(!tgt->flags.invalid || tgt->starttime == NULL){
952             kdc_log(0, "Bad request to validate ticket");
953             return KRB5KDC_ERR_BADOPTION;
954         }
955         if(*tgt->starttime > kdc_time){
956             kdc_log(0, "Early request to validate ticket");
957             return KRB5KRB_AP_ERR_TKT_NYV;
958         }
959         /* XXX  tkt = tgt */
960         et->flags.invalid = 0;
961     }else if(tgt->flags.invalid){
962         kdc_log(0, "Ticket-granting ticket has INVALID flag set");
963         return KRB5KRB_AP_ERR_TKT_INVALID;
964     }
965
966     if(f.forwardable){
967         if(!tgt->flags.forwardable){
968             kdc_log(0, "Bad request for forwardable ticket");
969             return KRB5KDC_ERR_BADOPTION;
970         }
971         et->flags.forwardable = 1;
972     }
973     if(f.forwarded){
974         if(!tgt->flags.forwardable){
975             kdc_log(0, "Request to forward non-forwardable ticket");
976             return KRB5KDC_ERR_BADOPTION;
977         }
978         et->flags.forwarded = 1;
979         et->caddr = b->addresses;
980     }
981     if(tgt->flags.forwarded)
982         et->flags.forwarded = 1;
983         
984     if(f.proxiable){
985         if(!tgt->flags.proxiable){
986             kdc_log(0, "Bad request for proxiable ticket");
987             return KRB5KDC_ERR_BADOPTION;
988         }
989         et->flags.proxiable = 1;
990     }
991     if(f.proxy){
992         if(!tgt->flags.proxiable){
993             kdc_log(0, "Request to proxy non-proxiable ticket");
994             return KRB5KDC_ERR_BADOPTION;
995         }
996         et->flags.proxy = 1;
997         et->caddr = b->addresses;
998     }
999     if(tgt->flags.proxy)
1000         et->flags.proxy = 1;
1001
1002     if(f.allow_postdate){
1003         if(!tgt->flags.may_postdate){
1004             kdc_log(0, "Bad request for post-datable ticket");
1005             return KRB5KDC_ERR_BADOPTION;
1006         }
1007         et->flags.may_postdate = 1;
1008     }
1009     if(f.postdated){
1010         if(!tgt->flags.may_postdate){
1011             kdc_log(0, "Bad request for postdated ticket");
1012             return KRB5KDC_ERR_BADOPTION;
1013         }
1014         if(b->from)
1015             *et->starttime = *b->from;
1016         et->flags.postdated = 1;
1017         et->flags.invalid = 1;
1018     }else if(b->from && *b->from > kdc_time + context->max_skew){
1019         kdc_log(0, "Ticket cannot be postdated");
1020         return KRB5KDC_ERR_CANNOT_POSTDATE;
1021     }
1022
1023     if(f.renewable){
1024         if(!tgt->flags.renewable){
1025             kdc_log(0, "Bad request for renewable ticket");
1026             return KRB5KDC_ERR_BADOPTION;
1027         }
1028         et->flags.renewable = 1;
1029         ALLOC(et->renew_till);
1030         fix_time(&b->rtime);
1031         *et->renew_till = *b->rtime;
1032     }
1033     if(f.renew){
1034         time_t old_life;
1035         if(!tgt->flags.renewable || tgt->renew_till == NULL){
1036             kdc_log(0, "Request to renew non-renewable ticket");
1037             return KRB5KDC_ERR_BADOPTION;
1038         }
1039         old_life = tgt->endtime;
1040         if(tgt->starttime)
1041             old_life -= *tgt->starttime;
1042         else
1043             old_life -= tgt->authtime;
1044         et->endtime = *et->starttime + old_life;
1045         if (et->renew_till != NULL)
1046             et->endtime = min(*et->renew_till, et->endtime);
1047     }       
1048     
1049     /* checks for excess flags */
1050     if(f.request_anonymous && !allow_anonymous){
1051         kdc_log(0, "Request for anonymous ticket");
1052         return KRB5KDC_ERR_BADOPTION;
1053     }
1054     return 0;
1055 }
1056
1057 static krb5_error_code
1058 fix_transited_encoding(krb5_boolean check_policy,
1059                        TransitedEncoding *tr, 
1060                        EncTicketPart *et, 
1061                        const char *client_realm, 
1062                        const char *server_realm, 
1063                        const char *tgt_realm)
1064 {
1065     krb5_error_code ret = 0;
1066     char **realms, **tmp;
1067     int num_realms;
1068     int i;
1069
1070     if(tr->tr_type != DOMAIN_X500_COMPRESS) {
1071         kdc_log(0, "Unknown transited type: %u", tr->tr_type);
1072         return KRB5KDC_ERR_TRTYPE_NOSUPP;
1073     }
1074
1075     ret = krb5_domain_x500_decode(context, 
1076                                   tr->contents,
1077                                   &realms, 
1078                                   &num_realms,
1079                                   client_realm,
1080                                   server_realm);
1081     if(ret){
1082         krb5_warn(context, ret, "Decoding transited encoding");
1083         return ret;
1084     }
1085     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
1086         /* not us, so add the previous realm to transited set */
1087         if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
1088             ret = ERANGE;
1089             goto free_realms;
1090         }
1091         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1092         if(tmp == NULL){
1093             ret = ENOMEM;
1094             goto free_realms;
1095         }
1096         realms = tmp;
1097         realms[num_realms] = strdup(tgt_realm);
1098         if(realms[num_realms] == NULL){
1099             ret = ENOMEM;
1100             goto free_realms;
1101         }
1102         num_realms++;
1103     }
1104     if(num_realms == 0) {
1105         if(strcmp(client_realm, server_realm)) 
1106             kdc_log(0, "cross-realm %s -> %s", client_realm, server_realm);
1107     } else {
1108         size_t l = 0;
1109         char *rs;
1110         for(i = 0; i < num_realms; i++)
1111             l += strlen(realms[i]) + 2;
1112         rs = malloc(l);
1113         if(rs != NULL) {
1114             *rs = '\0';
1115             for(i = 0; i < num_realms; i++) {
1116                 if(i > 0)
1117                     strlcat(rs, ", ", l);
1118                 strlcat(rs, realms[i], l);
1119             }
1120             kdc_log(0, "cross-realm %s -> %s via [%s]", client_realm, server_realm, rs);
1121             free(rs);
1122         }
1123     }
1124     if(check_policy) {
1125         ret = krb5_check_transited(context, client_realm, 
1126                                    server_realm, 
1127                                    realms, num_realms, NULL);
1128         if(ret) {
1129             krb5_warn(context, ret, "cross-realm %s -> %s", 
1130                       client_realm, server_realm);
1131             goto free_realms;
1132         }
1133         et->flags.transited_policy_checked = 1;
1134     }
1135     et->transited.tr_type = DOMAIN_X500_COMPRESS;
1136     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
1137     if(ret)
1138         krb5_warn(context, ret, "Encoding transited encoding");
1139   free_realms:
1140     for(i = 0; i < num_realms; i++)
1141         free(realms[i]);
1142     free(realms);
1143     return ret;
1144 }
1145
1146
1147 static krb5_error_code
1148 tgs_make_reply(KDC_REQ_BODY *b, 
1149                EncTicketPart *tgt, 
1150                EncTicketPart *adtkt, 
1151                AuthorizationData *auth_data,
1152                hdb_entry *server, 
1153                hdb_entry *client, 
1154                krb5_principal client_principal, 
1155                hdb_entry *krbtgt,
1156                krb5_enctype cetype,
1157                const char **e_text,
1158                krb5_data *reply)
1159 {
1160     KDC_REP rep;
1161     EncKDCRepPart ek;
1162     EncTicketPart et;
1163     KDCOptions f = b->kdc_options;
1164     krb5_error_code ret;
1165     krb5_enctype etype;
1166     Key *skey;
1167     EncryptionKey *ekey;
1168     
1169     if(adtkt) {
1170         int i;
1171         krb5_keytype kt;
1172         ekey = &adtkt->key;
1173         for(i = 0; i < b->etype.len; i++){
1174             ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
1175             if(ret)
1176                 continue;
1177             if(adtkt->key.keytype == kt)
1178                 break;
1179         }
1180         if(i == b->etype.len)
1181             return KRB5KDC_ERR_ETYPE_NOSUPP;
1182         etype = b->etype.val[i];
1183     }else{
1184         ret = find_keys(NULL, server, NULL, NULL, &skey, &etype, 
1185                         b->etype.val, b->etype.len);
1186         if(ret) {
1187             kdc_log(0, "Server has no support for etypes");
1188             return ret;
1189         }
1190         ekey = &skey->key;
1191     }
1192     
1193     memset(&rep, 0, sizeof(rep));
1194     memset(&et, 0, sizeof(et));
1195     memset(&ek, 0, sizeof(ek));
1196     
1197     rep.pvno = 5;
1198     rep.msg_type = krb_tgs_rep;
1199
1200     et.authtime = tgt->authtime;
1201     fix_time(&b->till);
1202     et.endtime = min(tgt->endtime, *b->till);
1203     ALLOC(et.starttime);
1204     *et.starttime = kdc_time;
1205     
1206     ret = check_tgs_flags(b, tgt, &et);
1207     if(ret)
1208         goto out;
1209
1210     /* We should check the transited encoding if:
1211        1) the request doesn't ask not to be checked
1212        2) globally enforcing a check
1213        3) principal requires checking
1214        4) we allow non-check per-principal, but principal isn't marked as allowing this
1215        5) we don't globally allow this
1216     */
1217
1218 #define GLOBAL_FORCE_TRANSITED_CHECK            (trpolicy == TRPOLICY_ALWAYS_CHECK)
1219 #define GLOBAL_ALLOW_PER_PRINCIPAL              (trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
1220 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK    (trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
1221 /* these will consult the database in future release */
1222 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
1223 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
1224
1225     ret = fix_transited_encoding(!f.disable_transited_check ||
1226                                  GLOBAL_FORCE_TRANSITED_CHECK ||
1227                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
1228                                  !((GLOBAL_ALLOW_PER_PRINCIPAL && 
1229                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
1230                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
1231                                  &tgt->transited, &et,
1232                                  *krb5_princ_realm(context, client_principal),
1233                                  *krb5_princ_realm(context, server->principal),
1234                                  *krb5_princ_realm(context, krbtgt->principal));
1235     if(ret)
1236         goto out;
1237
1238     copy_Realm(krb5_princ_realm(context, server->principal), 
1239                &rep.ticket.realm);
1240     krb5_principal2principalname(&rep.ticket.sname, server->principal);
1241     copy_Realm(&tgt->crealm, &rep.crealm);
1242     if (f.request_anonymous)
1243         make_anonymous_principalname (&tgt->cname);
1244     else
1245         copy_PrincipalName(&tgt->cname, &rep.cname);
1246     rep.ticket.tkt_vno = 5;
1247
1248     ek.caddr = et.caddr;
1249     if(et.caddr == NULL)
1250         et.caddr = tgt->caddr;
1251
1252     {
1253         time_t life;
1254         life = et.endtime - *et.starttime;
1255         if(client && client->max_life)
1256             life = min(life, *client->max_life);
1257         if(server->max_life)
1258             life = min(life, *server->max_life);
1259         et.endtime = *et.starttime + life;
1260     }
1261     if(f.renewable_ok && tgt->flags.renewable && 
1262        et.renew_till == NULL && et.endtime < *b->till){
1263         et.flags.renewable = 1;
1264         ALLOC(et.renew_till);
1265         *et.renew_till = *b->till;
1266     }
1267     if(et.renew_till){
1268         time_t renew;
1269         renew = *et.renew_till - et.authtime;
1270         if(client && client->max_renew)
1271             renew = min(renew, *client->max_renew);
1272         if(server->max_renew)
1273             renew = min(renew, *server->max_renew);
1274         *et.renew_till = et.authtime + renew;
1275     }
1276             
1277     if(et.renew_till){
1278         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
1279         *et.starttime = min(*et.starttime, *et.renew_till);
1280         et.endtime = min(et.endtime, *et.renew_till);
1281     }
1282     
1283     *et.starttime = min(*et.starttime, et.endtime);
1284
1285     if(*et.starttime == et.endtime){
1286         ret = KRB5KDC_ERR_NEVER_VALID;
1287         goto out;
1288     }
1289     if(et.renew_till && et.endtime == *et.renew_till){
1290         free(et.renew_till);
1291         et.renew_till = NULL;
1292         et.flags.renewable = 0;
1293     }
1294     
1295     et.flags.pre_authent = tgt->flags.pre_authent;
1296     et.flags.hw_authent  = tgt->flags.hw_authent;
1297     et.flags.anonymous   = tgt->flags.anonymous;
1298             
1299     /* XXX Check enc-authorization-data */
1300     et.authorization_data = auth_data;
1301
1302     krb5_generate_random_keyblock(context, etype, &et.key);
1303     et.crealm = tgt->crealm;
1304     et.cname = tgt->cname;
1305             
1306     ek.key = et.key;
1307     /* MIT must have at least one last_req */
1308     ek.last_req.len = 1;
1309     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1310     ek.nonce = b->nonce;
1311     ek.flags = et.flags;
1312     ek.authtime = et.authtime;
1313     ek.starttime = et.starttime;
1314     ek.endtime = et.endtime;
1315     ek.renew_till = et.renew_till;
1316     ek.srealm = rep.ticket.realm;
1317     ek.sname = rep.ticket.sname;
1318             
1319     /* It is somewhat unclear where the etype in the following
1320        encryption should come from. What we have is a session
1321        key in the passed tgt, and a list of preferred etypes
1322        *for the new ticket*. Should we pick the best possible
1323        etype, given the keytype in the tgt, or should we look
1324        at the etype list here as well?  What if the tgt
1325        session key is DES3 and we want a ticket with a (say)
1326        CAST session key. Should the DES3 etype be added to the
1327        etype list, even if we don't want a session key with
1328        DES3? */
1329     ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
1330                        0, &tgt->key, e_text, reply);
1331   out:
1332     free_TGS_REP(&rep);
1333     free_TransitedEncoding(&et.transited);
1334     if(et.starttime)
1335         free(et.starttime);
1336     if(et.renew_till)
1337         free(et.renew_till);
1338     free_LastReq(&ek.last_req);
1339     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1340     free_EncryptionKey(&et.key);
1341     return ret;
1342 }
1343
1344 static krb5_error_code
1345 tgs_check_authenticator(krb5_auth_context ac,
1346                         KDC_REQ_BODY *b, 
1347                         const char **e_text,
1348                         krb5_keyblock *key)
1349 {
1350     krb5_authenticator auth;
1351     size_t len;
1352     unsigned char *buf;
1353     size_t buf_size;
1354     krb5_error_code ret;
1355     krb5_crypto crypto;
1356     
1357     krb5_auth_con_getauthenticator(context, ac, &auth);
1358     if(auth->cksum == NULL){
1359         kdc_log(0, "No authenticator in request");
1360         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1361         goto out;
1362     }
1363     /*
1364      * according to RFC1510 it doesn't need to be keyed,
1365      * but according to the latest draft it needs to.
1366      */
1367     if (
1368 #if 0
1369 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1370         ||
1371 #endif
1372  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1373         kdc_log(0, "Bad checksum type in authenticator: %d", 
1374                 auth->cksum->cksumtype);
1375         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1376         goto out;
1377     }
1378                 
1379     /* XXX should not re-encode this */
1380     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1381     if(ret){
1382         kdc_log(0, "Failed to encode KDC-REQ-BODY: %s", 
1383                 krb5_get_err_text(context, ret));
1384         goto out;
1385     }
1386     if(buf_size != len) {
1387         free(buf);
1388         kdc_log(0, "Internal error in ASN.1 encoder");
1389         *e_text = "KDC internal error";
1390         ret = KRB5KRB_ERR_GENERIC;
1391         goto out;
1392     }
1393     ret = krb5_crypto_init(context, key, 0, &crypto);
1394     if (ret) {
1395         free(buf);
1396         kdc_log(0, "krb5_crypto_init failed: %s",
1397                 krb5_get_err_text(context, ret));
1398         goto out;
1399     }
1400     ret = krb5_verify_checksum(context,
1401                                crypto,
1402                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
1403                                buf, 
1404                                len,
1405                                auth->cksum);
1406     free(buf);
1407     krb5_crypto_destroy(context, crypto);
1408     if(ret){
1409         kdc_log(0, "Failed to verify checksum: %s", 
1410                 krb5_get_err_text(context, ret));
1411     }
1412 out:
1413     free_Authenticator(auth);
1414     free(auth);
1415     return ret;
1416 }
1417
1418 /*
1419  * return the realm of a krbtgt-ticket or NULL
1420  */
1421
1422 static Realm 
1423 get_krbtgt_realm(const PrincipalName *p)
1424 {
1425     if(p->name_string.len == 2
1426        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
1427         return p->name_string.val[1];
1428     else
1429         return NULL;
1430 }
1431
1432 static Realm
1433 find_rpath(Realm crealm, Realm srealm)
1434 {
1435     const char *new_realm = krb5_config_get_string(context,
1436                                                    NULL,
1437                                                    "capaths", 
1438                                                    crealm,
1439                                                    srealm,
1440                                                    NULL);
1441     return (Realm)new_realm;
1442 }
1443             
1444
1445 static krb5_boolean
1446 need_referral(krb5_principal server, krb5_realm **realms)
1447 {
1448     if(server->name.name_type != KRB5_NT_SRV_INST ||
1449        server->name.name_string.len != 2)
1450         return FALSE;
1451  
1452     return krb5_get_host_realm_int(context, server->name.name_string.val[1],
1453                                    FALSE, realms) == 0;
1454 }
1455
1456 static krb5_error_code
1457 tgs_rep2(KDC_REQ_BODY *b,
1458          PA_DATA *tgs_req,
1459          krb5_data *reply,
1460          const char *from,
1461          const struct sockaddr *from_addr,
1462          time_t **csec,
1463          int **cusec)
1464 {
1465     krb5_ap_req ap_req;
1466     krb5_error_code ret;
1467     krb5_principal princ;
1468     krb5_auth_context ac = NULL;
1469     krb5_ticket *ticket = NULL;
1470     krb5_flags ap_req_options;
1471     krb5_flags verify_ap_req_flags;
1472     const char *e_text = NULL;
1473     krb5_crypto crypto;
1474
1475     hdb_entry *krbtgt = NULL;
1476     EncTicketPart *tgt;
1477     Key *tkey;
1478     krb5_enctype cetype;
1479     krb5_principal cp = NULL;
1480     krb5_principal sp = NULL;
1481     AuthorizationData *auth_data = NULL;
1482
1483     *csec  = NULL;
1484     *cusec = NULL;
1485
1486     memset(&ap_req, 0, sizeof(ap_req));
1487     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1488     if(ret){
1489         kdc_log(0, "Failed to decode AP-REQ: %s", 
1490                 krb5_get_err_text(context, ret));
1491         goto out2;
1492     }
1493     
1494     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1495         /* XXX check for ticket.sname == req.sname */
1496         kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1497         ret = KRB5KDC_ERR_POLICY; /* ? */
1498         goto out2;
1499     }
1500     
1501     principalname2krb5_principal(&princ,
1502                                  ap_req.ticket.sname,
1503                                  ap_req.ticket.realm);
1504     
1505     ret = db_fetch(princ, &krbtgt);
1506
1507     if(ret) {
1508         char *p;
1509         krb5_unparse_name(context, princ, &p);
1510         krb5_free_principal(context, princ);
1511         kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
1512                 p, krb5_get_err_text(context, ret));
1513         free(p);
1514         ret = KRB5KRB_AP_ERR_NOT_US;
1515         goto out2;
1516     }
1517     
1518     if(ap_req.ticket.enc_part.kvno && 
1519        *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
1520         char *p;
1521
1522         krb5_unparse_name (context, princ, &p);
1523         krb5_free_principal(context, princ);
1524         kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)", 
1525                 *ap_req.ticket.enc_part.kvno,
1526                 krbtgt->kvno,
1527                 p);
1528         free (p);
1529         ret = KRB5KRB_AP_ERR_BADKEYVER;
1530         goto out2;
1531     }
1532
1533     ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
1534     if(ret){
1535         char *str;
1536         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1537         kdc_log(0, "No server key found for %s", str);
1538         free(str);
1539         ret = KRB5KRB_AP_ERR_BADKEYVER;
1540         goto out2;
1541     }
1542     
1543     if (b->kdc_options.validate)
1544         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1545     else
1546         verify_ap_req_flags = 0;
1547
1548     ret = krb5_verify_ap_req2(context,
1549                               &ac,
1550                               &ap_req,
1551                               princ,
1552                               &tkey->key,
1553                               verify_ap_req_flags,
1554                               &ap_req_options,
1555                               &ticket,
1556                               KRB5_KU_TGS_REQ_AUTH);
1557                              
1558     krb5_free_principal(context, princ);
1559     if(ret) {
1560         kdc_log(0, "Failed to verify AP-REQ: %s", 
1561                 krb5_get_err_text(context, ret));
1562         goto out2;
1563     }
1564
1565     {
1566         krb5_authenticator auth;
1567
1568         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1569         if (ret == 0) {
1570             *csec   = malloc(sizeof(**csec));
1571             if (*csec == NULL) {
1572                 krb5_free_authenticator(context, &auth);
1573                 kdc_log(0, "malloc failed");
1574                 goto out2;
1575             }
1576             **csec  = auth->ctime;
1577             *cusec  = malloc(sizeof(**cusec));
1578             if (*cusec == NULL) {
1579                 krb5_free_authenticator(context, &auth);
1580                 kdc_log(0, "malloc failed");
1581                 goto out2;
1582             }
1583             **csec  = auth->cusec;
1584             krb5_free_authenticator(context, &auth);
1585         }
1586     }
1587
1588     cetype = ap_req.authenticator.etype;
1589
1590     tgt = &ticket->ticket;
1591
1592     ret = tgs_check_authenticator(ac, b, &e_text, &tgt->key);
1593
1594     if (b->enc_authorization_data) {
1595         krb5_keyblock *subkey;
1596         krb5_data ad;
1597         ret = krb5_auth_con_getremotesubkey(context,
1598                                             ac,
1599                                             &subkey);
1600         if(ret){
1601             krb5_auth_con_free(context, ac);
1602             kdc_log(0, "Failed to get remote subkey: %s", 
1603                     krb5_get_err_text(context, ret));
1604             goto out2;
1605         }
1606         if(subkey == NULL){
1607             ret = krb5_auth_con_getkey(context, ac, &subkey);
1608             if(ret) {
1609                 krb5_auth_con_free(context, ac);
1610                 kdc_log(0, "Failed to get session key: %s", 
1611                         krb5_get_err_text(context, ret));
1612                 goto out2;
1613             }
1614         }
1615         if(subkey == NULL){
1616             krb5_auth_con_free(context, ac);
1617             kdc_log(0, "Failed to get key for enc-authorization-data");
1618             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1619             goto out2;
1620         }
1621         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1622         if (ret) {
1623             krb5_auth_con_free(context, ac);
1624             kdc_log(0, "krb5_crypto_init failed: %s",
1625                     krb5_get_err_text(context, ret));
1626             goto out2;
1627         }
1628         ret = krb5_decrypt_EncryptedData (context,
1629                                           crypto,
1630                                           KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1631                                           b->enc_authorization_data,
1632                                           &ad);
1633         krb5_crypto_destroy(context, crypto);
1634         if(ret){
1635             krb5_auth_con_free(context, ac);
1636             kdc_log(0, "Failed to decrypt enc-authorization-data");
1637             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1638             goto out2;
1639         }
1640         krb5_free_keyblock(context, subkey);
1641         ALLOC(auth_data);
1642         ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1643         if(ret){
1644             krb5_auth_con_free(context, ac);
1645             free(auth_data);
1646             auth_data = NULL;
1647             kdc_log(0, "Failed to decode authorization data");
1648             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1649             goto out2;
1650         }
1651     }
1652
1653     krb5_auth_con_free(context, ac);
1654
1655     if(ret){
1656         kdc_log(0, "Failed to verify authenticator: %s", 
1657                 krb5_get_err_text(context, ret));
1658         goto out2;
1659     }
1660     
1661     {
1662         PrincipalName *s;
1663         Realm r;
1664         char *spn = NULL, *cpn = NULL;
1665         hdb_entry *server = NULL, *client = NULL;
1666         int loop = 0;
1667         EncTicketPart adtkt;
1668         char opt_str[128];
1669
1670         s = b->sname;
1671         r = b->realm;
1672         if(b->kdc_options.enc_tkt_in_skey){
1673             Ticket *t;
1674             hdb_entry *uu;
1675             krb5_principal p;
1676             Key *tkey;
1677             
1678             if(b->additional_tickets == NULL || 
1679                b->additional_tickets->len == 0){
1680                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1681                 kdc_log(0, "No second ticket present in request");
1682                 goto out;
1683             }
1684             t = &b->additional_tickets->val[0];
1685             if(!get_krbtgt_realm(&t->sname)){
1686                 kdc_log(0, "Additional ticket is not a ticket-granting ticket");
1687                 ret = KRB5KDC_ERR_POLICY;
1688                 goto out2;
1689             }
1690             principalname2krb5_principal(&p, t->sname, t->realm);
1691             ret = db_fetch(p, &uu);
1692             krb5_free_principal(context, p);
1693             if(ret){
1694                 if (ret == HDB_ERR_NOENTRY)
1695                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1696                 goto out;
1697             }
1698             ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
1699             if(ret){
1700                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1701                 goto out;
1702             }
1703             ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0);
1704
1705             if(ret)
1706                 goto out;
1707             s = &adtkt.cname;
1708             r = adtkt.crealm;
1709         }
1710
1711         principalname2krb5_principal(&sp, *s, r);
1712         krb5_unparse_name(context, sp, &spn);   
1713         principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1714         krb5_unparse_name(context, cp, &cpn);
1715         unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
1716                        opt_str, sizeof(opt_str));
1717         if(*opt_str)
1718             kdc_log(0, "TGS-REQ %s from %s for %s [%s]", 
1719                     cpn, from, spn, opt_str);
1720         else
1721             kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1722     server_lookup:
1723         ret = db_fetch(sp, &server);
1724
1725         if(ret){
1726             Realm req_rlm, new_rlm;
1727             krb5_realm *realms;
1728
1729             if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1730                 if(loop++ < 2) {
1731                     new_rlm = find_rpath(tgt->crealm, req_rlm);
1732                     if(new_rlm) {
1733                         kdc_log(5, "krbtgt for realm %s not found, trying %s", 
1734                                 req_rlm, new_rlm);
1735                         krb5_free_principal(context, sp);
1736                         free(spn);
1737                         krb5_make_principal(context, &sp, r, 
1738                                             KRB5_TGS_NAME, new_rlm, NULL);
1739                         krb5_unparse_name(context, sp, &spn);   
1740                         goto server_lookup;
1741                     }
1742                 }
1743             } else if(need_referral(sp, &realms)) {
1744                 if (strcmp(realms[0], sp->realm) != 0) {
1745                     kdc_log(5, "returning a referral to realm %s for "
1746                             "server %s that was not found",
1747                             realms[0], spn);
1748                     krb5_free_principal(context, sp);
1749                     free(spn);
1750                     krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1751                                         realms[0], NULL);
1752                     krb5_unparse_name(context, sp, &spn);
1753                     krb5_free_host_realm(context, realms);
1754                     goto server_lookup;
1755                 }
1756                 krb5_free_host_realm(context, realms);
1757             }
1758             kdc_log(0, "Server not found in database: %s: %s", spn,
1759                     krb5_get_err_text(context, ret));
1760             if (ret == HDB_ERR_NOENTRY)
1761                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1762             goto out;
1763         }
1764
1765         ret = db_fetch(cp, &client);
1766         if(ret)
1767             kdc_log(1, "Client not found in database: %s: %s",
1768                     cpn, krb5_get_err_text(context, ret));
1769 #if 0
1770         /* XXX check client only if same realm as krbtgt-instance */
1771         if(ret){
1772             kdc_log(0, "Client not found in database: %s: %s",
1773                     cpn, krb5_get_err_text(context, ret));
1774             if (ret == HDB_ERR_NOENTRY)
1775                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1776             goto out;
1777         }
1778 #endif
1779
1780         if(strcmp(krb5_principal_get_realm(context, sp),
1781                   krb5_principal_get_comp_string(context, krbtgt->principal, 1)) != 0) {
1782             char *tpn;
1783             ret = krb5_unparse_name(context, krbtgt->principal, &tpn);
1784             kdc_log(0, "Request with wrong krbtgt: %s", (ret == 0) ? tpn : "<unknown>");
1785             if(ret == 0)
1786                 free(tpn);
1787             ret = KRB5KRB_AP_ERR_NOT_US;
1788             goto out;
1789             
1790         }
1791
1792         ret = check_flags(client, cpn, server, spn, FALSE);
1793         if(ret)
1794             goto out;
1795
1796         if((b->kdc_options.validate || b->kdc_options.renew) && 
1797            !krb5_principal_compare(context, 
1798                                    krbtgt->principal,
1799                                    server->principal)){
1800             kdc_log(0, "Inconsistent request.");
1801             ret = KRB5KDC_ERR_SERVER_NOMATCH;
1802             goto out;
1803         }
1804
1805         /* check for valid set of addresses */
1806         if(!check_addresses(tgt->caddr, from_addr)) {
1807             ret = KRB5KRB_AP_ERR_BADADDR;
1808             kdc_log(0, "Request from wrong address");
1809             goto out;
1810         }
1811         
1812         ret = tgs_make_reply(b, 
1813                              tgt, 
1814                              b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, 
1815                              auth_data,
1816                              server, 
1817                              client, 
1818                              cp, 
1819                              krbtgt, 
1820                              cetype, 
1821                              &e_text,
1822                              reply);
1823         
1824     out:
1825         free(spn);
1826         free(cpn);
1827             
1828         if(server)
1829             free_ent(server);
1830         if(client)
1831             free_ent(client);
1832     }
1833 out2:
1834     if(ret) {
1835         krb5_mk_error(context,
1836                       ret,
1837                       e_text,
1838                       NULL,
1839                       cp,
1840                       sp,
1841                       NULL,
1842                       NULL,
1843                       reply);
1844         free(*csec);
1845         free(*cusec);
1846         *csec  = NULL;
1847         *cusec = NULL;
1848     }
1849     krb5_free_principal(context, cp);
1850     krb5_free_principal(context, sp);
1851     if (ticket) {
1852         krb5_free_ticket(context, ticket);
1853         free(ticket);
1854     }
1855     free_AP_REQ(&ap_req);
1856     if(auth_data){
1857         free_AuthorizationData(auth_data);
1858         free(auth_data);
1859     }
1860
1861     if(krbtgt)
1862         free_ent(krbtgt);
1863
1864     return ret;
1865 }
1866
1867
1868 krb5_error_code
1869 tgs_rep(KDC_REQ *req, 
1870         krb5_data *data,
1871         const char *from,
1872         struct sockaddr *from_addr)
1873 {
1874     krb5_error_code ret;
1875     int i = 0;
1876     PA_DATA *tgs_req = NULL;
1877     time_t *csec = NULL;
1878     int *cusec = NULL;
1879
1880     if(req->padata == NULL){
1881         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1882         kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1883         goto out;
1884     }
1885     
1886     tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1887
1888     if(tgs_req == NULL){
1889         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1890         
1891         kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1892         goto out;
1893     }
1894     ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr,
1895                    &csec, &cusec);
1896 out:
1897     if(ret && data->data == NULL){
1898         krb5_mk_error(context,
1899                       ret,
1900                       NULL,
1901                       NULL,
1902                       NULL,
1903                       NULL,
1904                       csec,
1905                       cusec,
1906                       data);
1907     }
1908     free(csec);
1909     free(cusec);
1910     return 0;
1911 }