xref: /freebsd/crypto/heimdal/kdc/kerberos5.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
1 /*
2  * Copyright (c) 1997-2000 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.123 2001/01/30 01:44:08 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 	  int *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 (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 		      0,
634 		      reply);
635 	free(buf);
636 	kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
637 	ret = 0;
638 	goto out2;
639     }
640 
641     ret = find_keys(client, server, &ckey, &cetype, &skey, &setype,
642 		    b->etype.val, b->etype.len);
643     if(ret) {
644 	kdc_log(0, "Server/client has no support for etypes");
645 	goto out;
646     }
647 
648     {
649 	char *cet;
650 	char *set;
651 
652 	ret = krb5_enctype_to_string(context, cetype, &cet);
653 	if(ret == 0) {
654 	    ret = krb5_enctype_to_string(context, setype, &set);
655 	    if (ret == 0) {
656 		kdc_log(5, "Using %s/%s", cet, set);
657 		free(set);
658 	    } else
659 	    free(cet);
660 	} else
661 	    kdc_log(5, "Using e-types %d/%d", cetype, setype);
662     }
663 
664     {
665 	char str[128];
666 	unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str));
667 	if(*str)
668 	    kdc_log(2, "Requested flags: %s", str);
669     }
670 
671 
672     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey
673        || (f.request_anonymous && !allow_anonymous)) {
674 	ret = KRB5KDC_ERR_BADOPTION;
675 	kdc_log(0, "Bad KDC options -- %s", client_name);
676 	goto out;
677     }
678 
679     rep.pvno = 5;
680     rep.msg_type = krb_as_rep;
681     copy_Realm(&b->realm, &rep.crealm);
682     if (f.request_anonymous)
683 	make_anonymous_principalname (&rep.cname);
684     else
685 	copy_PrincipalName(b->cname, &rep.cname);
686     rep.ticket.tkt_vno = 5;
687     copy_Realm(&b->realm, &rep.ticket.realm);
688     copy_PrincipalName(b->sname, &rep.ticket.sname);
689 
690     et.flags.initial = 1;
691     if(client->flags.forwardable && server->flags.forwardable)
692 	et.flags.forwardable = f.forwardable;
693     else if (f.forwardable) {
694 	ret = KRB5KDC_ERR_POLICY;
695 	kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
696 	goto out;
697     }
698     if(client->flags.proxiable && server->flags.proxiable)
699 	et.flags.proxiable = f.proxiable;
700     else if (f.proxiable) {
701 	ret = KRB5KDC_ERR_POLICY;
702 	kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
703 	goto out;
704     }
705     if(client->flags.postdate && server->flags.postdate)
706 	et.flags.may_postdate = f.allow_postdate;
707     else if (f.allow_postdate){
708 	ret = KRB5KDC_ERR_POLICY;
709 	kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
710 	goto out;
711     }
712 
713     /* check for valid set of addresses */
714     if(!check_addresses(b->addresses, from_addr)) {
715 	ret = KRB5KRB_AP_ERR_BADADDR;
716 	kdc_log(0, "Bad address list requested -- %s", client_name);
717 	goto out;
718     }
719 
720     krb5_generate_random_keyblock(context, setype, &et.key);
721     copy_PrincipalName(&rep.cname, &et.cname);
722     copy_Realm(&b->realm, &et.crealm);
723 
724     {
725 	time_t start;
726 	time_t t;
727 
728 	start = et.authtime = kdc_time;
729 
730 	if(f.postdated && req->req_body.from){
731 	    ALLOC(et.starttime);
732 	    start = *et.starttime = *req->req_body.from;
733 	    et.flags.invalid = 1;
734 	    et.flags.postdated = 1; /* XXX ??? */
735 	}
736 	fix_time(&b->till);
737 	t = *b->till;
738 
739 	/* be careful not overflowing */
740 
741 	if(client->max_life)
742 	    t = start + min(t - start, *client->max_life);
743 	if(server->max_life)
744 	    t = start + min(t - start, *server->max_life);
745 #if 0
746 	t = min(t, start + realm->max_life);
747 #endif
748 	et.endtime = t;
749 	if(f.renewable_ok && et.endtime < *b->till){
750 	    f.renewable = 1;
751 	    if(b->rtime == NULL){
752 		ALLOC(b->rtime);
753 		*b->rtime = 0;
754 	    }
755 	    if(*b->rtime < *b->till)
756 		*b->rtime = *b->till;
757 	}
758 	if(f.renewable && b->rtime){
759 	    t = *b->rtime;
760 	    if(t == 0)
761 		t = MAX_TIME;
762 	    if(client->max_renew)
763 		t = start + min(t - start, *client->max_renew);
764 	    if(server->max_renew)
765 		t = start + min(t - start, *server->max_renew);
766 #if 0
767 	    t = min(t, start + realm->max_renew);
768 #endif
769 	    ALLOC(et.renew_till);
770 	    *et.renew_till = t;
771 	    et.flags.renewable = 1;
772 	}
773     }
774 
775     if (f.request_anonymous)
776 	et.flags.anonymous = 1;
777 
778     if(b->addresses){
779 	ALLOC(et.caddr);
780 	copy_HostAddresses(b->addresses, et.caddr);
781     }
782 
783     {
784 	krb5_data empty_string;
785 
786 	krb5_data_zero(&empty_string);
787 	et.transited.tr_type = DOMAIN_X500_COMPRESS;
788 	et.transited.contents = empty_string;
789     }
790 
791     copy_EncryptionKey(&et.key, &ek.key);
792 
793     /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
794      * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
795      * incapable of correctly decoding SEQUENCE OF's of zero length.
796      *
797      * To fix this, always send at least one no-op last_req
798      *
799      * If there's a pw_end or valid_end we will use that,
800      * otherwise just a dummy lr.
801      */
802     ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
803     ek.last_req.len = 0;
804     if (client->pw_end
805 	&& (kdc_warn_pwexpire == 0
806 	    || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
807 	ek.last_req.val[ek.last_req.len].lr_type  = 6;
808 	ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
809 	++ek.last_req.len;
810     }
811     if (client->valid_end) {
812 	ek.last_req.val[ek.last_req.len].lr_type  = 7;
813 	ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
814 	++ek.last_req.len;
815     }
816     if (ek.last_req.len == 0) {
817 	ek.last_req.val[ek.last_req.len].lr_type  = 0;
818 	ek.last_req.val[ek.last_req.len].lr_value = 0;
819 	++ek.last_req.len;
820     }
821     ek.nonce = b->nonce;
822     if (client->valid_end || client->pw_end) {
823 	ALLOC(ek.key_expiration);
824 	if (client->valid_end) {
825 	    if (client->pw_end)
826 		*ek.key_expiration = min(*client->valid_end, *client->pw_end);
827 	    else
828 		*ek.key_expiration = *client->valid_end;
829 	} else
830 	    *ek.key_expiration = *client->pw_end;
831     } else
832 	ek.key_expiration = NULL;
833     ek.flags = et.flags;
834     ek.authtime = et.authtime;
835     if (et.starttime) {
836 	ALLOC(ek.starttime);
837 	*ek.starttime = *et.starttime;
838     }
839     ek.endtime = et.endtime;
840     if (et.renew_till) {
841 	ALLOC(ek.renew_till);
842 	*ek.renew_till = *et.renew_till;
843     }
844     copy_Realm(&rep.ticket.realm, &ek.srealm);
845     copy_PrincipalName(&rep.ticket.sname, &ek.sname);
846     if(et.caddr){
847 	ALLOC(ek.caddr);
848 	copy_HostAddresses(et.caddr, ek.caddr);
849     }
850 
851     set_salt_padata (&rep.padata, ckey->salt);
852     ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key,
853 		       client->kvno, &ckey->key, reply);
854     free_EncTicketPart(&et);
855     free_EncKDCRepPart(&ek);
856     free_AS_REP(&rep);
857 out:
858     if(ret){
859 	krb5_mk_error(context,
860 		      ret,
861 		      e_text,
862 		      NULL,
863 		      client_princ,
864 		      server_princ,
865 		      0,
866 		      reply);
867 	ret = 0;
868     }
869 out2:
870     krb5_free_principal(context, client_princ);
871     free(client_name);
872     krb5_free_principal(context, server_princ);
873     free(server_name);
874     if(client)
875 	free_ent(client);
876     if(server)
877 	free_ent(server);
878     return ret;
879 }
880 
881 
882 static krb5_error_code
883 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
884 {
885     KDCOptions f = b->kdc_options;
886 
887     if(f.validate){
888 	if(!tgt->flags.invalid || tgt->starttime == NULL){
889 	    kdc_log(0, "Bad request to validate ticket");
890 	    return KRB5KDC_ERR_BADOPTION;
891 	}
892 	if(*tgt->starttime > kdc_time){
893 	    kdc_log(0, "Early request to validate ticket");
894 	    return KRB5KRB_AP_ERR_TKT_NYV;
895 	}
896 	/* XXX  tkt = tgt */
897 	et->flags.invalid = 0;
898     }else if(tgt->flags.invalid){
899 	kdc_log(0, "Ticket-granting ticket has INVALID flag set");
900 	return KRB5KRB_AP_ERR_TKT_INVALID;
901     }
902 
903     if(f.forwardable){
904 	if(!tgt->flags.forwardable){
905 	    kdc_log(0, "Bad request for forwardable ticket");
906 	    return KRB5KDC_ERR_BADOPTION;
907 	}
908 	et->flags.forwardable = 1;
909     }
910     if(f.forwarded){
911 	if(!tgt->flags.forwardable){
912 	    kdc_log(0, "Request to forward non-forwardable ticket");
913 	    return KRB5KDC_ERR_BADOPTION;
914 	}
915 	et->flags.forwarded = 1;
916 	et->caddr = b->addresses;
917     }
918     if(tgt->flags.forwarded)
919 	et->flags.forwarded = 1;
920 
921     if(f.proxiable){
922 	if(!tgt->flags.proxiable){
923 	    kdc_log(0, "Bad request for proxiable ticket");
924 	    return KRB5KDC_ERR_BADOPTION;
925 	}
926 	et->flags.proxiable = 1;
927     }
928     if(f.proxy){
929 	if(!tgt->flags.proxiable){
930 	    kdc_log(0, "Request to proxy non-proxiable ticket");
931 	    return KRB5KDC_ERR_BADOPTION;
932 	}
933 	et->flags.proxy = 1;
934 	et->caddr = b->addresses;
935     }
936     if(tgt->flags.proxy)
937 	et->flags.proxy = 1;
938 
939     if(f.allow_postdate){
940 	if(!tgt->flags.may_postdate){
941 	    kdc_log(0, "Bad request for post-datable ticket");
942 	    return KRB5KDC_ERR_BADOPTION;
943 	}
944 	et->flags.may_postdate = 1;
945     }
946     if(f.postdated){
947 	if(!tgt->flags.may_postdate){
948 	    kdc_log(0, "Bad request for postdated ticket");
949 	    return KRB5KDC_ERR_BADOPTION;
950 	}
951 	if(b->from)
952 	    *et->starttime = *b->from;
953 	et->flags.postdated = 1;
954 	et->flags.invalid = 1;
955     }else if(b->from && *b->from > kdc_time + context->max_skew){
956 	kdc_log(0, "Ticket cannot be postdated");
957 	return KRB5KDC_ERR_CANNOT_POSTDATE;
958     }
959 
960     if(f.renewable){
961 	if(!tgt->flags.renewable){
962 	    kdc_log(0, "Bad request for renewable ticket");
963 	    return KRB5KDC_ERR_BADOPTION;
964 	}
965 	et->flags.renewable = 1;
966 	ALLOC(et->renew_till);
967 	fix_time(&b->rtime);
968 	*et->renew_till = *b->rtime;
969     }
970     if(f.renew){
971 	time_t old_life;
972 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
973 	    kdc_log(0, "Request to renew non-renewable ticket");
974 	    return KRB5KDC_ERR_BADOPTION;
975 	}
976 	old_life = tgt->endtime;
977 	if(tgt->starttime)
978 	    old_life -= *tgt->starttime;
979 	else
980 	    old_life -= tgt->authtime;
981 	et->endtime = min(*et->renew_till, *et->starttime + old_life);
982     }
983 
984     /* checks for excess flags */
985     if(f.request_anonymous && !allow_anonymous){
986 	kdc_log(0, "Request for anonymous ticket");
987 	return KRB5KDC_ERR_BADOPTION;
988     }
989     return 0;
990 }
991 
992 static krb5_error_code
993 fix_transited_encoding(TransitedEncoding *tr,
994 		       const char *client_realm,
995 		       const char *server_realm,
996 		       const char *tgt_realm)
997 {
998     krb5_error_code ret = 0;
999     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)){
1000 	char **realms = NULL, **tmp;
1001 	int num_realms = 0;
1002 	int i;
1003 	if(tr->tr_type && tr->contents.length != 0) {
1004 	    if(tr->tr_type != DOMAIN_X500_COMPRESS){
1005 		kdc_log(0, "Unknown transited type: %u",
1006 			tr->tr_type);
1007 		return KRB5KDC_ERR_TRTYPE_NOSUPP;
1008 	    }
1009 	    ret = krb5_domain_x500_decode(tr->contents,
1010 					  &realms,
1011 					  &num_realms,
1012 					  client_realm,
1013 					  server_realm);
1014 	    if(ret){
1015 		krb5_warn(context, ret, "Decoding transited encoding");
1016 		return ret;
1017 	    }
1018 	}
1019 	tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
1020 	if(tmp == NULL){
1021 	    ret = ENOMEM;
1022 	    goto free_realms;
1023 	}
1024 	realms = tmp;
1025 	realms[num_realms] = strdup(tgt_realm);
1026 	if(realms[num_realms] == NULL){
1027 	    ret = ENOMEM;
1028 	    goto free_realms;
1029 	}
1030 	num_realms++;
1031 	free_TransitedEncoding(tr);
1032 	tr->tr_type = DOMAIN_X500_COMPRESS;
1033 	ret = krb5_domain_x500_encode(realms, num_realms, &tr->contents);
1034 	if(ret)
1035 	    krb5_warn(context, ret, "Encoding transited encoding");
1036     free_realms:
1037 	for(i = 0; i < num_realms; i++)
1038 	    free(realms[i]);
1039 	free(realms);
1040     }
1041     return ret;
1042 }
1043 
1044 
1045 static krb5_error_code
1046 tgs_make_reply(KDC_REQ_BODY *b,
1047 	       EncTicketPart *tgt,
1048 	       EncTicketPart *adtkt,
1049 	       AuthorizationData *auth_data,
1050 	       hdb_entry *server,
1051 	       hdb_entry *client,
1052 	       krb5_principal client_principal,
1053 	       hdb_entry *krbtgt,
1054 	       krb5_enctype cetype,
1055 	       krb5_data *reply)
1056 {
1057     KDC_REP rep;
1058     EncKDCRepPart ek;
1059     EncTicketPart et;
1060     KDCOptions f = b->kdc_options;
1061     krb5_error_code ret;
1062     krb5_enctype etype;
1063     Key *skey;
1064     EncryptionKey *ekey;
1065 
1066     if(adtkt) {
1067 	int i;
1068 	krb5_keytype kt;
1069 	ekey = &adtkt->key;
1070 	for(i = 0; i < b->etype.len; i++){
1071 	    ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt);
1072 	    if(ret)
1073 		continue;
1074 	    if(adtkt->key.keytype == kt)
1075 		break;
1076 	}
1077 	if(i == b->etype.len)
1078 	    return KRB5KDC_ERR_ETYPE_NOSUPP;
1079 	etype = b->etype.val[i];
1080     }else{
1081 	ret = find_keys(NULL, server, NULL, NULL, &skey, &etype,
1082 			b->etype.val, b->etype.len);
1083 	if(ret) {
1084 	    kdc_log(0, "Server has no support for etypes");
1085 	    return ret;
1086 	}
1087 	ekey = &skey->key;
1088     }
1089 
1090     memset(&rep, 0, sizeof(rep));
1091     memset(&et, 0, sizeof(et));
1092     memset(&ek, 0, sizeof(ek));
1093 
1094     rep.pvno = 5;
1095     rep.msg_type = krb_tgs_rep;
1096 
1097     et.authtime = tgt->authtime;
1098     fix_time(&b->till);
1099     et.endtime = min(tgt->endtime, *b->till);
1100     ALLOC(et.starttime);
1101     *et.starttime = kdc_time;
1102 
1103     ret = check_tgs_flags(b, tgt, &et);
1104     if(ret)
1105 	return ret;
1106 
1107     copy_TransitedEncoding(&tgt->transited, &et.transited);
1108     ret = fix_transited_encoding(&et.transited,
1109 				 *krb5_princ_realm(context, client_principal),
1110 				 *krb5_princ_realm(context, server->principal),
1111 				 *krb5_princ_realm(context, krbtgt->principal));
1112     if(ret){
1113 	free_TransitedEncoding(&et.transited);
1114 	return ret;
1115     }
1116 
1117 
1118     copy_Realm(krb5_princ_realm(context, server->principal),
1119 	       &rep.ticket.realm);
1120     krb5_principal2principalname(&rep.ticket.sname, server->principal);
1121     copy_Realm(&tgt->crealm, &rep.crealm);
1122     if (f.request_anonymous)
1123 	make_anonymous_principalname (&tgt->cname);
1124     else
1125 	copy_PrincipalName(&tgt->cname, &rep.cname);
1126     rep.ticket.tkt_vno = 5;
1127 
1128     ek.caddr = et.caddr;
1129     if(et.caddr == NULL)
1130 	et.caddr = tgt->caddr;
1131 
1132     {
1133 	time_t life;
1134 	life = et.endtime - *et.starttime;
1135 	if(client && client->max_life)
1136 	    life = min(life, *client->max_life);
1137 	if(server->max_life)
1138 	    life = min(life, *server->max_life);
1139 	et.endtime = *et.starttime + life;
1140     }
1141     if(f.renewable_ok && tgt->flags.renewable &&
1142        et.renew_till == NULL && et.endtime < *b->till){
1143 	et.flags.renewable = 1;
1144 	ALLOC(et.renew_till);
1145 	*et.renew_till = *b->till;
1146     }
1147     if(et.renew_till){
1148 	time_t renew;
1149 	renew = *et.renew_till - et.authtime;
1150 	if(client && client->max_renew)
1151 	    renew = min(renew, *client->max_renew);
1152 	if(server->max_renew)
1153 	    renew = min(renew, *server->max_renew);
1154 	*et.renew_till = et.authtime + renew;
1155     }
1156 
1157     if(et.renew_till){
1158 	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
1159 	*et.starttime = min(*et.starttime, *et.renew_till);
1160 	et.endtime = min(et.endtime, *et.renew_till);
1161     }
1162 
1163     *et.starttime = min(*et.starttime, et.endtime);
1164 
1165     if(*et.starttime == et.endtime){
1166 	ret = KRB5KDC_ERR_NEVER_VALID;
1167 	goto out;
1168     }
1169     if(et.renew_till && et.endtime == *et.renew_till){
1170 	free(et.renew_till);
1171 	et.renew_till = NULL;
1172 	et.flags.renewable = 0;
1173     }
1174 
1175     et.flags.pre_authent = tgt->flags.pre_authent;
1176     et.flags.hw_authent  = tgt->flags.hw_authent;
1177     et.flags.anonymous   = tgt->flags.anonymous;
1178 
1179     /* XXX Check enc-authorization-data */
1180     et.authorization_data = auth_data;
1181 
1182     krb5_generate_random_keyblock(context, etype, &et.key);
1183     et.crealm = tgt->crealm;
1184     et.cname = tgt->cname;
1185 
1186     ek.key = et.key;
1187     /* MIT must have at least one last_req */
1188     ek.last_req.len = 1;
1189     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
1190     ek.nonce = b->nonce;
1191     ek.flags = et.flags;
1192     ek.authtime = et.authtime;
1193     ek.starttime = et.starttime;
1194     ek.endtime = et.endtime;
1195     ek.renew_till = et.renew_till;
1196     ek.srealm = rep.ticket.realm;
1197     ek.sname = rep.ticket.sname;
1198 
1199     /* It is somewhat unclear where the etype in the following
1200        encryption should come from. What we have is a session
1201        key in the passed tgt, and a list of preferred etypes
1202        *for the new ticket*. Should we pick the best possible
1203        etype, given the keytype in the tgt, or should we look
1204        at the etype list here as well?  What if the tgt
1205        session key is DES3 and we want a ticket with a (say)
1206        CAST session key. Should the DES3 etype be added to the
1207        etype list, even if we don't want a session key with
1208        DES3? */
1209     ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey,
1210 		       0, &tgt->key, reply);
1211 out:
1212     free_TGS_REP(&rep);
1213     free_TransitedEncoding(&et.transited);
1214     if(et.starttime)
1215 	free(et.starttime);
1216     if(et.renew_till)
1217 	free(et.renew_till);
1218     free_LastReq(&ek.last_req);
1219     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1220     free_EncryptionKey(&et.key);
1221     return ret;
1222 }
1223 
1224 static krb5_error_code
1225 tgs_check_authenticator(krb5_auth_context ac,
1226 			KDC_REQ_BODY *b,
1227 			krb5_keyblock *key)
1228 {
1229     krb5_authenticator auth;
1230     size_t len;
1231     unsigned char buf[8192];
1232     krb5_error_code ret;
1233     krb5_crypto crypto;
1234 
1235     krb5_auth_getauthenticator(context, ac, &auth);
1236     if(auth->cksum == NULL){
1237 	kdc_log(0, "No authenticator in request");
1238 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1239 	goto out;
1240     }
1241     /*
1242      * according to RFC1510 it doesn't need to be keyed,
1243      * but according to the latest draft it needs to.
1244      */
1245     if (
1246 #if 0
1247 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1248 	||
1249 #endif
1250  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1251 	kdc_log(0, "Bad checksum type in authenticator: %d",
1252 		auth->cksum->cksumtype);
1253 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1254 	goto out;
1255     }
1256 
1257     /* XXX should not re-encode this */
1258     ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf),
1259 			      b, &len);
1260     if(ret){
1261 	kdc_log(0, "Failed to encode KDC-REQ-BODY: %s",
1262 		krb5_get_err_text(context, ret));
1263 	goto out;
1264     }
1265     ret = krb5_crypto_init(context, key, 0, &crypto);
1266     if (ret) {
1267 	kdc_log(0, "krb5_crypto_init failed: %s",
1268 		krb5_get_err_text(context, ret));
1269 	goto out;
1270     }
1271     ret = krb5_verify_checksum(context,
1272 			       crypto,
1273 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
1274 			       buf + sizeof(buf) - len,
1275 			       len,
1276 			       auth->cksum);
1277     krb5_crypto_destroy(context, crypto);
1278     if(ret){
1279 	kdc_log(0, "Failed to verify checksum: %s",
1280 		krb5_get_err_text(context, ret));
1281     }
1282 out:
1283     free_Authenticator(auth);
1284     free(auth);
1285     return ret;
1286 }
1287 
1288 static Realm
1289 is_krbtgt(PrincipalName *p)
1290 {
1291     if(p->name_string.len == 2 && strcmp(p->name_string.val[0], "krbtgt") == 0)
1292 	return p->name_string.val[1];
1293     else
1294 	return NULL;
1295 }
1296 
1297 static Realm
1298 find_rpath(Realm r)
1299 {
1300     const char *new_realm = krb5_config_get_string(context,
1301 						   NULL,
1302 						   "libdefaults",
1303 						   "capath",
1304 						   r,
1305 						   NULL);
1306     return (Realm)new_realm;
1307 }
1308 
1309 
1310 static krb5_error_code
1311 tgs_rep2(KDC_REQ_BODY *b,
1312 	 PA_DATA *tgs_req,
1313 	 krb5_data *reply,
1314 	 const char *from,
1315 	 struct sockaddr *from_addr)
1316 {
1317     krb5_ap_req ap_req;
1318     krb5_error_code ret;
1319     krb5_principal princ;
1320     krb5_auth_context ac = NULL;
1321     krb5_ticket *ticket = NULL;
1322     krb5_flags ap_req_options;
1323     krb5_flags verify_ap_req_flags;
1324     const char *e_text = NULL;
1325     krb5_crypto crypto;
1326 
1327     hdb_entry *krbtgt = NULL;
1328     EncTicketPart *tgt;
1329     Key *tkey;
1330     krb5_enctype cetype;
1331     krb5_principal cp = NULL;
1332     krb5_principal sp = NULL;
1333     AuthorizationData *auth_data = NULL;
1334 
1335     memset(&ap_req, 0, sizeof(ap_req));
1336     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1337     if(ret){
1338 	kdc_log(0, "Failed to decode AP-REQ: %s",
1339 		krb5_get_err_text(context, ret));
1340 	goto out2;
1341     }
1342 
1343     if(!is_krbtgt(&ap_req.ticket.sname)){
1344 	/* XXX check for ticket.sname == req.sname */
1345 	kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1346 	ret = KRB5KDC_ERR_POLICY; /* ? */
1347 	goto out2;
1348     }
1349 
1350     principalname2krb5_principal(&princ,
1351 				 ap_req.ticket.sname,
1352 				 ap_req.ticket.realm);
1353 
1354     ret = db_fetch(princ, &krbtgt);
1355 
1356     if(ret) {
1357 	char *p;
1358 	krb5_unparse_name(context, princ, &p);
1359 	kdc_log(0, "Ticket-granting ticket not found in database: %s: %s",
1360 		p, krb5_get_err_text(context, ret));
1361 	free(p);
1362 	ret = KRB5KRB_AP_ERR_NOT_US;
1363 	goto out2;
1364     }
1365 
1366     if(ap_req.ticket.enc_part.kvno &&
1367        *ap_req.ticket.enc_part.kvno != krbtgt->kvno){
1368 	char *p;
1369 
1370 	krb5_unparse_name (context, princ, &p);
1371 	kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)",
1372 		*ap_req.ticket.enc_part.kvno,
1373 		krbtgt->kvno,
1374 		p);
1375 	free (p);
1376 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1377 	goto out2;
1378     }
1379 
1380     ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey);
1381     if(ret){
1382 	char *str;
1383 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1384 	kdc_log(0, "No server key found for %s", str);
1385 	free(str);
1386 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1387 	goto out2;
1388     }
1389 
1390     if (b->kdc_options.validate)
1391 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1392     else
1393 	verify_ap_req_flags = 0;
1394 
1395     ret = krb5_verify_ap_req2(context,
1396 			      &ac,
1397 			      &ap_req,
1398 			      princ,
1399 			      &tkey->key,
1400 			      verify_ap_req_flags,
1401 			      &ap_req_options,
1402 			      &ticket,
1403 			      KRB5_KU_TGS_REQ_AUTH);
1404 
1405     krb5_free_principal(context, princ);
1406     if(ret) {
1407 	kdc_log(0, "Failed to verify AP-REQ: %s",
1408 		krb5_get_err_text(context, ret));
1409 	goto out2;
1410     }
1411 
1412     cetype = ap_req.authenticator.etype;
1413 
1414     tgt = &ticket->ticket;
1415 
1416     ret = tgs_check_authenticator(ac, b, &tgt->key);
1417 
1418     if (b->enc_authorization_data) {
1419 	krb5_keyblock *subkey;
1420 	krb5_data ad;
1421 	ret = krb5_auth_con_getremotesubkey(context,
1422 					    ac,
1423 					    &subkey);
1424 	if(ret){
1425 	    krb5_auth_con_free(context, ac);
1426 	    kdc_log(0, "Failed to get remote subkey: %s",
1427 		    krb5_get_err_text(context, ret));
1428 	    goto out2;
1429 	}
1430 	if(subkey == NULL){
1431 	    ret = krb5_auth_con_getkey(context, ac, &subkey);
1432 	    if(ret) {
1433 		krb5_auth_con_free(context, ac);
1434 		kdc_log(0, "Failed to get session key: %s",
1435 			krb5_get_err_text(context, ret));
1436 		goto out2;
1437 	    }
1438 	}
1439 	if(subkey == NULL){
1440 	    krb5_auth_con_free(context, ac);
1441 	    kdc_log(0, "Failed to get key for enc-authorization-data");
1442 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1443 	    goto out2;
1444 	}
1445 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
1446 	if (ret) {
1447 	    krb5_auth_con_free(context, ac);
1448 	    kdc_log(0, "krb5_crypto_init failed: %s",
1449 		    krb5_get_err_text(context, ret));
1450 	    goto out2;
1451 	}
1452 	ret = krb5_decrypt_EncryptedData (context,
1453 					  crypto,
1454 					  KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
1455 					  b->enc_authorization_data,
1456 					  &ad);
1457 	krb5_crypto_destroy(context, crypto);
1458 	if(ret){
1459 	    krb5_auth_con_free(context, ac);
1460 	    kdc_log(0, "Failed to decrypt enc-authorization-data");
1461 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1462 	    goto out2;
1463 	}
1464 	krb5_free_keyblock(context, subkey);
1465 	ALLOC(auth_data);
1466 	ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL);
1467 	if(ret){
1468 	    krb5_auth_con_free(context, ac);
1469 	    free(auth_data);
1470 	    auth_data = NULL;
1471 	    kdc_log(0, "Failed to decode authorization data");
1472 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1473 	    goto out2;
1474 	}
1475     }
1476 
1477     krb5_auth_con_free(context, ac);
1478 
1479     if(ret){
1480 	kdc_log(0, "Failed to verify authenticator: %s",
1481 		krb5_get_err_text(context, ret));
1482 	goto out2;
1483     }
1484 
1485     {
1486 	PrincipalName *s;
1487 	Realm r;
1488 	char *spn = NULL, *cpn = NULL;
1489 	hdb_entry *server = NULL, *client = NULL;
1490 	int loop = 0;
1491 	EncTicketPart adtkt;
1492 	char opt_str[128];
1493 
1494 	s = b->sname;
1495 	r = b->realm;
1496 	if(b->kdc_options.enc_tkt_in_skey){
1497 	    Ticket *t;
1498 	    hdb_entry *uu;
1499 	    krb5_principal p;
1500 	    Key *tkey;
1501 
1502 	    if(b->additional_tickets == NULL ||
1503 	       b->additional_tickets->len == 0){
1504 		ret = KRB5KDC_ERR_BADOPTION; /* ? */
1505 		kdc_log(0, "No second ticket present in request");
1506 		goto out;
1507 	    }
1508 	    t = &b->additional_tickets->val[0];
1509 	    if(!is_krbtgt(&t->sname)){
1510 		kdc_log(0, "Additional ticket is not a ticket-granting ticket");
1511 		ret = KRB5KDC_ERR_POLICY;
1512 		goto out2;
1513 	    }
1514 	    principalname2krb5_principal(&p, t->sname, t->realm);
1515 	    ret = db_fetch(p, &uu);
1516 	    krb5_free_principal(context, p);
1517 	    if(ret){
1518 		if (ret == ENOENT)
1519 		    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1520 		goto out;
1521 	    }
1522 	    ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey);
1523 	    if(ret){
1524 		ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1525 		goto out;
1526 	    }
1527 	    ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0);
1528 
1529 	    if(ret)
1530 		goto out;
1531 	    s = &adtkt.cname;
1532 	    r = adtkt.crealm;
1533 	}
1534 
1535 	principalname2krb5_principal(&sp, *s, r);
1536 	krb5_unparse_name(context, sp, &spn);
1537 	principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1538 	krb5_unparse_name(context, cp, &cpn);
1539 	unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units,
1540 		       opt_str, sizeof(opt_str));
1541 	if(*opt_str)
1542 	    kdc_log(0, "TGS-REQ %s from %s for %s [%s]",
1543 		    cpn, from, spn, opt_str);
1544 	else
1545 	    kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1546     server_lookup:
1547 	ret = db_fetch(sp, &server);
1548 
1549 	if(ret){
1550 	    Realm req_rlm, new_rlm;
1551 	    if(loop++ < 2 && (req_rlm = is_krbtgt(&sp->name))){
1552 		new_rlm = find_rpath(req_rlm);
1553 		if(new_rlm) {
1554 		    kdc_log(5, "krbtgt for realm %s not found, trying %s",
1555 			    req_rlm, new_rlm);
1556 		    krb5_free_principal(context, sp);
1557 		    free(spn);
1558 		    krb5_make_principal(context, &sp, r,
1559 					"krbtgt", new_rlm, NULL);
1560 		    krb5_unparse_name(context, sp, &spn);
1561 		    goto server_lookup;
1562 		}
1563 	    }
1564 	    kdc_log(0, "Server not found in database: %s: %s", spn,
1565 		    krb5_get_err_text(context, ret));
1566 	    if (ret == ENOENT)
1567 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1568 	    goto out;
1569 	}
1570 
1571 	ret = db_fetch(cp, &client);
1572 	if(ret)
1573 	    kdc_log(1, "Client not found in database: %s: %s",
1574 		    cpn, krb5_get_err_text(context, ret));
1575 #if 0
1576 	/* XXX check client only if same realm as krbtgt-instance */
1577 	if(ret){
1578 	    kdc_log(0, "Client not found in database: %s: %s",
1579 		    cpn, krb5_get_err_text(context, ret));
1580 	    if (ret == ENOENT)
1581 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1582 	    goto out;
1583 	}
1584 #endif
1585 
1586 	ret = check_flags(client, cpn, server, spn, FALSE);
1587 	if(ret)
1588 	    goto out;
1589 
1590 	if((b->kdc_options.validate || b->kdc_options.renew) &&
1591 	   !krb5_principal_compare(context,
1592 				   krbtgt->principal,
1593 				   server->principal)){
1594 	    kdc_log(0, "Inconsistent request.");
1595 	    ret = KRB5KDC_ERR_SERVER_NOMATCH;
1596 	    goto out;
1597 	}
1598 
1599 	/* check for valid set of addresses */
1600 	if(!check_addresses(tgt->caddr, from_addr)) {
1601 	    ret = KRB5KRB_AP_ERR_BADADDR;
1602 	    kdc_log(0, "Request from wrong address");
1603 	    goto out;
1604 	}
1605 
1606 	ret = tgs_make_reply(b,
1607 			     tgt,
1608 			     b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL,
1609 			     auth_data,
1610 			     server,
1611 			     client,
1612 			     cp,
1613 			     krbtgt,
1614 			     cetype,
1615 			     reply);
1616 
1617     out:
1618 	free(spn);
1619 	free(cpn);
1620 
1621 	if(server)
1622 	    free_ent(server);
1623 	if(client)
1624 	    free_ent(client);
1625     }
1626 out2:
1627     if(ret)
1628 	krb5_mk_error(context,
1629 		      ret,
1630 		      e_text,
1631 		      NULL,
1632 		      cp,
1633 		      sp,
1634 		      0,
1635 		      reply);
1636     krb5_free_principal(context, cp);
1637     krb5_free_principal(context, sp);
1638     if (ticket) {
1639 	krb5_free_ticket(context, ticket);
1640 	free(ticket);
1641     }
1642     free_AP_REQ(&ap_req);
1643     if(auth_data){
1644 	free_AuthorizationData(auth_data);
1645 	free(auth_data);
1646     }
1647 
1648     if(krbtgt)
1649 	free_ent(krbtgt);
1650     return ret;
1651 }
1652 
1653 
1654 krb5_error_code
1655 tgs_rep(KDC_REQ *req,
1656 	krb5_data *data,
1657 	const char *from,
1658 	struct sockaddr *from_addr)
1659 {
1660     krb5_error_code ret;
1661     int i = 0;
1662     PA_DATA *tgs_req = NULL;
1663 
1664     if(req->padata == NULL){
1665 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1666 	kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1667 	goto out;
1668     }
1669 
1670     tgs_req = find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1671 
1672     if(tgs_req == NULL){
1673 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1674 
1675 	kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1676 	goto out;
1677     }
1678     ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr);
1679 out:
1680     if(ret && data->data == NULL){
1681 	krb5_mk_error(context,
1682 		      ret,
1683 		      NULL,
1684 		      NULL,
1685 		      NULL,
1686 		      NULL,
1687 		      0,
1688 		      data);
1689     }
1690     return 0;
1691 }
1692