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