fixes for build headers
[heimdal.git] / kdc / kerberos5.c
blobfcdc4c6b71d6220551d97c582a7e4df848d3875b
1 /*
2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "kdc_locl.h"
41 RCSID("$Id$");
43 #define MAX_TIME ((time_t)((1U << 31) - 1))
45 static void
46 fix_time(time_t **t)
48 if(*t == NULL){
49 ALLOC(*t);
50 **t = MAX_TIME;
52 if(**t == 0) **t = MAX_TIME; /* fix for old clients */
55 krb5_error_code
56 as_rep(KDC_REQ *req,
57 krb5_data *reply,
58 const char *from)
60 KDC_REQ_BODY *b = &req->req_body;
61 AS_REP rep;
62 KDCOptions f = b->kdc_options;
63 hdb_entry *client = NULL, *server = NULL;
64 int etype;
65 EncTicketPart et;
66 EncKDCRepPart ek;
67 krb5_principal client_princ, server_princ;
68 char *client_name, *server_name;
69 krb5_error_code ret = 0;
70 const char *e_text = NULL;
71 int i;
73 Key *ckey, *skey, *ekey;
75 if(b->sname == NULL){
76 server_name = "<unknown server>";
77 ret = KRB5KRB_ERR_GENERIC;
78 e_text = "No server in request";
79 } else{
80 principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
81 krb5_unparse_name(context, server_princ, &server_name);
84 if(b->cname == NULL){
85 client_name = "<unknown client>";
86 ret = KRB5KRB_ERR_GENERIC;
87 e_text = "No client in request";
88 } else {
89 principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
90 krb5_unparse_name(context, client_princ, &client_name);
92 kdc_log(0, "AS-REQ %s from %s for %s",
93 client_name, from, server_name);
95 if(ret)
96 goto out;
98 client = db_fetch(client_princ);
99 if(client == NULL){
100 kdc_log(0, "UNKNOWN -- %s", client_name);
101 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
102 goto out;
105 if (client->valid_start && *client->valid_start > kdc_time) {
106 kdc_log(0, "Client not yet valid -- %s", client_name);
107 ret = KRB5KDC_ERR_CLIENT_NOTYET;
108 goto out;
111 if (client->valid_end && *client->valid_end < kdc_time) {
112 kdc_log(0, "Client expired -- %s", client_name);
113 ret = KRB5KDC_ERR_NAME_EXP;
114 goto out;
117 server = db_fetch(server_princ);
119 if(server == NULL){
120 kdc_log(0, "UNKNOWN -- %s", server_name);
121 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
122 goto out;
125 if (server->valid_start && *server->valid_start > kdc_time) {
126 kdc_log(0, "Server not yet valid -- %s", server_name);
127 ret = KRB5KDC_ERR_SERVICE_NOTYET;
128 goto out;
131 if (server->valid_end && *server->valid_end < kdc_time) {
132 kdc_log(0, "Server expired -- %s", server_name);
133 ret = KRB5KDC_ERR_SERVICE_EXP;
134 goto out;
137 if(!client->flags.client){
138 ret = KRB5KDC_ERR_POLICY;
139 kdc_log(0, "Principal may not act as client -- %s",
140 client_name);
141 goto out;
143 if(!server->flags.server){
144 ret = KRB5KDC_ERR_POLICY;
145 kdc_log(0, "Principal (%s) may not act as server -- %s",
146 server_name, client_name);
147 goto out;
150 if (client->pw_end && *client->pw_end < kdc_time
151 && !server->flags.change_pw) {
152 ret = KRB5KDC_ERR_KEY_EXPIRED;
153 kdc_log(0, "Client (%s)'s key has expired", client_name);
154 goto out;
157 /* Find appropriate key */
158 for(i = 0; i < b->etype.len; i++){
159 ret = hdb_etype2key(context, client, b->etype.val[i], &ckey);
160 if(ret)
161 continue;
162 ret = hdb_etype2key(context, server, b->etype.val[i], &skey);
163 if(ret)
164 continue;
165 break;
168 if(ret){
169 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
170 kdc_log(0, "No support for etypes -- %s", client_name);
171 goto out;
174 etype = b->etype.val[i];
176 memset(&et, 0, sizeof(et));
177 memset(&ek, 0, sizeof(ek));
179 if(req->padata){
180 int i;
181 PA_DATA *pa;
182 int found_pa = 0;
183 kdc_log(5, "Looking for pa-data -- %s", client_name);
184 for(i = 0; i < req->padata->len; i++){
185 PA_DATA *pa = &req->padata->val[i];
186 if(pa->padata_type == pa_enc_timestamp){
187 krb5_data ts_data;
188 PA_ENC_TS_ENC p;
189 time_t patime;
190 size_t len;
191 EncryptedData enc_data;
193 kdc_log(5, "Found pa-enc-timestamp -- %s",
194 client_name);
195 found_pa = 1;
197 ret = decode_EncryptedData(pa->padata_value.data,
198 pa->padata_value.length,
199 &enc_data,
200 &len);
201 if (ret) {
202 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
203 kdc_log(5, "Failed to decode PA-DATA -- %s",
204 client_name);
205 goto out;
208 ekey = unseal_key(ckey);
210 ret = krb5_decrypt (context,
211 enc_data.cipher.data,
212 enc_data.cipher.length,
213 enc_data.etype,
214 &ekey->key,
215 &ts_data);
216 hdb_free_key(ekey);
217 free_EncryptedData(&enc_data);
218 if(ret){
219 e_text = "Failed to decrypt PA-DATA";
220 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
221 client_name);
222 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
223 continue;
225 ret = decode_PA_ENC_TS_ENC(ts_data.data,
226 ts_data.length,
228 &len);
229 krb5_data_free(&ts_data);
230 if(ret){
231 e_text = "Failed to decode PA-ENC-TS-ENC";
232 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
233 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
234 client_name);
235 continue;
237 patime = p.patimestamp;
238 free_PA_ENC_TS_ENC(&p);
239 if (abs(kdc_time - p.patimestamp) > context->max_skew) {
240 ret = KRB5KDC_ERR_PREAUTH_FAILED;
241 krb5_mk_error (context,
242 ret,
243 "Too large time skew",
244 NULL,
245 client_princ,
246 server_princ,
248 reply);
249 kdc_log(0, "Too large time skew -- %s",
250 client_name);
251 goto out2;
253 et.flags.pre_authent = 1;
254 kdc_log(2, "Pre-authentication succeded -- %s",
255 client_name);
256 break;
257 } else {
258 kdc_log(5, "Found pa-data of type %d -- %s",
259 pa->padata_type, client_name);
262 /* XXX */
263 if(found_pa == 0 && require_preauth)
264 goto use_pa;
265 /* We come here if we found a pa-enc-timestamp, but if there
266 was some problem with it, other than too large skew */
267 if(et.flags.pre_authent == 0){
268 kdc_log(0, "%s -- %s", e_text, client_name);
269 e_text = NULL;
270 goto out;
272 }else if (require_preauth
273 || client->flags.require_preauth) {
274 METHOD_DATA method_data;
275 PA_DATA pa_data;
276 u_char buf[16];
277 size_t len;
278 krb5_data foo_data;
280 use_pa:
281 method_data.len = 1;
282 method_data.val = &pa_data;
284 pa_data.padata_type = pa_enc_timestamp;
285 pa_data.padata_value.length = 0;
286 pa_data.padata_value.data = NULL;
288 encode_METHOD_DATA(buf + sizeof(buf) - 1,
289 sizeof(buf),
290 &method_data,
291 &len);
292 foo_data.length = len;
293 foo_data.data = buf + sizeof(buf) - len;
295 ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
296 krb5_mk_error(context,
297 ret,
298 "Need to use PA-ENC-TIMESTAMP",
299 &foo_data,
300 client_princ,
301 server_princ,
303 reply);
305 kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
306 goto out2;
309 kdc_log(2, "Using etype %d -- %s", etype, client_name);
311 memset(&rep, 0, sizeof(rep));
312 rep.pvno = 5;
313 rep.msg_type = krb_as_rep;
314 copy_Realm(&b->realm, &rep.crealm);
315 copy_PrincipalName(b->cname, &rep.cname);
316 rep.ticket.tkt_vno = 5;
317 copy_Realm(&b->realm, &rep.ticket.realm);
318 copy_PrincipalName(b->sname, &rep.ticket.sname);
320 if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey){
321 ret = KRB5KDC_ERR_BADOPTION;
322 kdc_log(0, "Bad KDC options -- %s", client_name);
323 goto out;
326 et.flags.initial = 1;
327 if(client->flags.forwardable && server->flags.forwardable)
328 et.flags.forwardable = f.forwardable;
329 else if (f.forwardable) {
330 ret = KRB5KDC_ERR_POLICY;
331 kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
332 goto out;
334 if(client->flags.proxiable && server->flags.proxiable)
335 et.flags.proxiable = f.proxiable;
336 else if (f.proxiable) {
337 ret = KRB5KDC_ERR_POLICY;
338 kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
339 goto out;
341 if(client->flags.postdate && server->flags.postdate)
342 et.flags.may_postdate = f.allow_postdate;
343 else if (f.allow_postdate){
344 ret = KRB5KDC_ERR_POLICY;
345 kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
346 goto out;
349 krb5_generate_random_keyblock(context, ckey->key.keytype, &et.key);
350 copy_PrincipalName(b->cname, &et.cname);
351 copy_Realm(&b->realm, &et.crealm);
354 time_t start;
355 time_t t;
357 start = et.authtime = kdc_time;
359 if(f.postdated && req->req_body.from){
360 ALLOC(et.starttime);
361 start = *et.starttime = *req->req_body.from;
362 et.flags.invalid = 1;
363 et.flags.postdated = 1; /* XXX ??? */
364 kdc_log(2, "Postdated ticket requested -- %s",
365 client_name);
367 fix_time(&b->till);
368 t = *b->till;
369 if(client->max_life)
370 t = min(t, start + *client->max_life);
371 if(server->max_life)
372 t = min(t, start + *server->max_life);
373 #if 0
374 t = min(t, start + realm->max_life);
375 #endif
376 et.endtime = t;
377 if(f.renewable_ok && et.endtime < *b->till){
378 f.renewable = 1;
379 if(b->rtime == NULL){
380 ALLOC(b->rtime);
381 *b->rtime = 0;
383 if(*b->rtime < *b->till)
384 *b->rtime = *b->till;
386 if(f.renewable && b->rtime){
387 t = *b->rtime;
388 if(t == 0)
389 t = MAX_TIME;
390 if(client->max_renew)
391 t = min(t, start + *client->max_renew);
392 if(server->max_renew)
393 t = min(t, start + *server->max_renew);
394 #if 0
395 t = min(t, start + realm->max_renew);
396 #endif
397 ALLOC(et.renew_till);
398 *et.renew_till = t;
399 et.flags.renewable = 1;
403 if(b->addresses){
404 ALLOC(et.caddr);
405 copy_HostAddresses(b->addresses, et.caddr);
408 copy_EncryptionKey(&et.key, &ek.key);
410 /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
411 * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
412 * incapable to correctly decode vectors of zero length.
414 * To fix this, always send at least one no-op last_req
416 * If there's a pw_end or valid_end we will use that,
417 * otherwise just a dummy lr.
419 ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
420 ek.last_req.len = 0;
421 if (client->pw_end
422 && (kdc_warn_pwexpire == 0
423 || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
424 ek.last_req.val[ek.last_req.len].lr_type = 6;
425 ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
426 ++ek.last_req.len;
428 if (client->valid_end) {
429 ek.last_req.val[ek.last_req.len].lr_type = 7;
430 ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
431 ++ek.last_req.len;
433 if (ek.last_req.len == 0) {
434 ek.last_req.val[ek.last_req.len].lr_type = 0;
435 ek.last_req.val[ek.last_req.len].lr_value = 0;
436 ++ek.last_req.len;
438 ek.nonce = b->nonce;
439 if (client->valid_end || client->pw_end) {
440 ALLOC(ek.key_expiration);
441 if (client->valid_end)
442 if (client->pw_end)
443 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
444 else
445 *ek.key_expiration = *client->valid_end;
446 else
447 *ek.key_expiration = *client->pw_end;
448 } else
449 ek.key_expiration = NULL;
450 ek.flags = et.flags;
451 ek.authtime = et.authtime;
452 if (et.starttime) {
453 ALLOC(ek.starttime);
454 *ek.starttime = *et.starttime;
455 } else
456 ek.starttime = et.starttime;
457 ek.endtime = et.endtime;
458 if (et.renew_till) {
459 ALLOC(ek.renew_till);
460 *ek.renew_till = *et.renew_till;
461 } else
462 ek.renew_till = et.renew_till;
463 copy_Realm(&rep.ticket.realm, &ek.srealm);
464 copy_PrincipalName(&rep.ticket.sname, &ek.sname);
465 if(et.caddr){
466 ALLOC(ek.caddr);
467 copy_HostAddresses(et.caddr, ek.caddr);
471 unsigned char buf[1024]; /* XXX The data could be indefinite */
472 size_t len;
474 ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf),
475 &et, &len);
476 free_EncTicketPart(&et);
477 if(ret) {
478 kdc_log(0, "Failed to encode ticket -- %s", client);
479 goto out;
482 ekey = unseal_key(skey);
483 krb5_encrypt_EncryptedData(context,
484 buf + sizeof(buf) - len,
485 len,
486 etype,
487 server->kvno,
488 &ekey->key,
489 &rep.ticket.enc_part);
490 hdb_free_key(ekey);
492 ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf),
493 &ek, &len);
494 free_EncKDCRepPart(&ek);
495 if(ret) {
496 kdc_log(0, "Failed to encode KDC-REP -- %s", client_name);
497 goto out;
499 ekey = unseal_key(ckey);
500 krb5_encrypt_EncryptedData(context,
501 buf + sizeof(buf) - len,
502 len,
503 etype,
504 client->kvno,
505 &ekey->key,
506 &rep.enc_part);
507 hdb_free_key(ekey);
508 if(ckey->salt){
509 ALLOC(rep.padata);
510 rep.padata->len = 1;
511 rep.padata->val = calloc(1, sizeof(*rep.padata->val));
512 rep.padata->val->padata_type = pa_pw_salt;
513 copy_octet_string(ckey->salt, &rep.padata->val->padata_value);
516 ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
517 free_AS_REP(&rep);
518 if(ret) {
519 kdc_log(0, "Failed to encode AS-REP -- %s", client_name);
520 goto out;
523 krb5_data_copy(reply, buf + sizeof(buf) - len, len);
525 out:
526 if(ret){
527 krb5_mk_error(context,
528 ret,
529 e_text,
530 NULL,
531 client_princ,
532 server_princ,
534 reply);
536 out2:
537 krb5_free_principal(context, client_princ);
538 free(client_name);
539 krb5_free_principal(context, server_princ);
540 free(server_name);
541 if(client){
542 hdb_free_entry(context, client);
543 free(client);
545 if(server){
546 hdb_free_entry(context, server);
547 free(server);
550 return ret;
554 static krb5_error_code
555 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
557 KDCOptions f = b->kdc_options;
559 if(f.validate){
560 if(!tgt->flags.invalid || tgt->starttime == NULL){
561 kdc_log(0, "Bad request to validate ticket");
562 return KRB5KDC_ERR_BADOPTION;
564 if(*tgt->starttime < kdc_time){
565 kdc_log(0, "Early request to validate ticket");
566 return KRB5KRB_AP_ERR_TKT_NYV;
568 /* XXX tkt = tgt */
569 et->flags.invalid = 0;
570 }else if(tgt->flags.invalid){
571 kdc_log(0, "Ticket-granting ticket has INVALID flag set");
572 return KRB5KRB_AP_ERR_TKT_INVALID;
575 if(f.forwardable){
576 if(!tgt->flags.forwardable){
577 kdc_log(0, "Bad request for forwardable ticket");
578 return KRB5KDC_ERR_BADOPTION;
580 et->flags.forwardable = 1;
582 if(f.forwarded){
583 if(!tgt->flags.forwardable){
584 kdc_log(0, "Request to forward non-forwardable ticket");
585 return KRB5KDC_ERR_BADOPTION;
587 et->flags.forwarded = 1;
588 et->caddr = b->addresses;
590 if(tgt->flags.forwarded)
591 et->flags.forwarded = 1;
593 if(f.proxiable){
594 if(!tgt->flags.proxiable){
595 kdc_log(0, "Bad request for proxiable ticket");
596 return KRB5KDC_ERR_BADOPTION;
598 et->flags.proxiable = 1;
600 if(f.proxy){
601 if(!tgt->flags.proxiable){
602 kdc_log(0, "Request to proxy non-proxiable ticket");
603 return KRB5KDC_ERR_BADOPTION;
605 et->flags.proxy = 1;
606 et->caddr = b->addresses;
608 if(tgt->flags.proxy)
609 et->flags.proxy = 1;
611 if(f.allow_postdate){
612 if(!tgt->flags.may_postdate){
613 kdc_log(0, "Bad request for post-datable ticket");
614 return KRB5KDC_ERR_BADOPTION;
616 et->flags.may_postdate = 1;
618 if(f.postdated){
619 if(!tgt->flags.may_postdate){
620 kdc_log(0, "Bad request for postdated ticket");
621 return KRB5KDC_ERR_BADOPTION;
623 if(b->from)
624 *et->starttime = *b->from;
625 et->flags.postdated = 1;
626 et->flags.invalid = 1;
627 }else if(b->from && *b->from > kdc_time + context->max_skew){
628 kdc_log(0, "Ticket cannot be postdated");
629 return KRB5KDC_ERR_CANNOT_POSTDATE;
632 if(f.renewable){
633 if(!tgt->flags.renewable){
634 kdc_log(0, "Bad request for renewable ticket");
635 return KRB5KDC_ERR_BADOPTION;
637 et->flags.renewable = 1;
638 ALLOC(et->renew_till);
639 *et->renew_till = *b->rtime;
641 if(f.renew){
642 time_t old_life;
643 if(!tgt->flags.renewable || tgt->renew_till == NULL){
644 kdc_log(0, "Request to renew non-renewable ticket");
645 return KRB5KDC_ERR_BADOPTION;
647 old_life = tgt->endtime;
648 if(tgt->starttime)
649 old_life -= *tgt->starttime;
650 else
651 old_life -= tgt->authtime;
652 et->endtime = *et->starttime + old_life;
655 /* check for excess flags */
656 return 0;
659 static krb5_error_code
660 tgs_make_reply(KDC_REQ_BODY *b, EncTicketPart *tgt,
661 hdb_entry *server, hdb_entry *client, krb5_data *reply)
663 KDC_REP rep;
664 EncKDCRepPart ek;
665 EncTicketPart et;
666 KDCOptions f = b->kdc_options;
667 krb5_error_code ret;
668 int i;
669 krb5_enctype etype;
670 Key *skey, *ekey;
672 /* Find appropriate key */
673 for(i = 0; i < b->etype.len; i++){
674 ret = hdb_etype2key(context, server, b->etype.val[i], &skey);
675 if(ret == 0)
676 break;
679 if(ret){
680 kdc_log(0, "Failed to find requested etype");
681 return KRB5KDC_ERR_ETYPE_NOSUPP;
684 etype = b->etype.val[i];
686 memset(&rep, 0, sizeof(rep));
687 memset(&et, 0, sizeof(et));
688 memset(&ek, 0, sizeof(ek));
690 rep.pvno = 5;
691 rep.msg_type = krb_tgs_rep;
693 et.authtime = tgt->authtime;
694 fix_time(&b->till);
695 et.endtime = min(tgt->endtime, *b->till);
696 ALLOC(et.starttime);
697 *et.starttime = kdc_time;
699 ret = check_tgs_flags(b, tgt, &et);
700 if(ret)
701 return ret;
703 copy_Realm(krb5_princ_realm(context, server->principal),
704 &rep.ticket.realm);
705 krb5_principal2principalname(&rep.ticket.sname, server->principal);
706 copy_Realm(&tgt->crealm, &rep.crealm);
707 copy_PrincipalName(&tgt->cname, &rep.cname);
708 rep.ticket.tkt_vno = 5;
710 ek.caddr = et.caddr;
711 if(et.caddr == NULL)
712 et.caddr = tgt->caddr;
715 time_t life;
716 life = et.endtime - *et.starttime;
717 if(client->max_life)
718 life = min(life, *client->max_life);
719 if(server->max_life)
720 life = min(life, *server->max_life);
721 et.endtime = *et.starttime + life;
723 if(f.renewable_ok && tgt->flags.renewable &&
724 et.renew_till == NULL && et.endtime < *b->till){
725 et.flags.renewable = 1;
726 ALLOC(et.renew_till);
727 *et.renew_till = *b->till;
729 if(et.renew_till){
730 time_t renew;
731 renew = *et.renew_till - et.authtime;
732 if(client->max_renew)
733 renew = min(renew, *client->max_renew);
734 if(server->max_renew)
735 renew = min(renew, *server->max_renew);
736 *et.renew_till = et.authtime + renew;
739 if(et.renew_till){
740 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
741 *et.starttime = min(*et.starttime, *et.renew_till);
742 et.endtime = min(et.endtime, *et.renew_till);
745 *et.starttime = min(*et.starttime, et.endtime);
747 if(*et.starttime == et.endtime){
748 ret = KRB5KDC_ERR_NEVER_VALID;
749 goto out;
751 if(et.renew_till && et.endtime == *et.renew_till){
752 free(et.renew_till);
753 et.renew_till = NULL;
754 et.flags.renewable = 0;
757 et.flags.pre_authent = tgt->flags.pre_authent;
758 et.flags.hw_authent = tgt->flags.hw_authent;
760 /* XXX Check enc-authorization-data */
762 krb5_generate_random_keyblock(context,
763 skey->key.keytype,
764 &et.key);
765 et.crealm = tgt->crealm;
766 et.cname = tgt->cname;
767 /* do cross realm stuff */
768 et.transited = tgt->transited;
771 ek.key = et.key;
772 /* MIT must have at least one last_req */
773 ek.last_req.len = 1;
774 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
775 ek.nonce = b->nonce;
776 ek.flags = et.flags;
777 ek.authtime = et.authtime;
778 ek.starttime = et.starttime;
779 ek.endtime = et.endtime;
780 ek.renew_till = et.renew_till;
781 ek.srealm = rep.ticket.realm;
782 ek.sname = rep.ticket.sname;
785 unsigned char buf[1024]; /* XXX The data could be indefinite */
786 size_t len;
787 ret = encode_EncTicketPart(buf + sizeof(buf) - 1,
788 sizeof(buf), &et, &len);
789 if(ret){
790 kdc_log(0, "Failed to encode EncTicketPart: %s",
791 krb5_get_err_text(context, ret));
792 goto out;
794 ekey = unseal_key(skey);
795 krb5_encrypt_EncryptedData(context, buf + sizeof(buf) - len, len,
796 etype,
797 server->kvno,
798 &ekey->key,
799 &rep.ticket.enc_part);
800 hdb_free_key(ekey);
802 ret = encode_EncTGSRepPart(buf + sizeof(buf) - 1,
803 sizeof(buf), &ek, &len);
804 if(ret){
805 kdc_log(0, "Failed to encode EncTicketPart: %s",
806 krb5_get_err_text(context, ret));
807 goto out;
810 /* It is somewhat unclear where the etype in the following
811 encryption should come from. What we have is a session
812 key in the passed tgt, and a list of preferred etypes
813 *for the new ticket*. Should we pick the best possible
814 etype, given the keytype in the tgt, or should we look
815 at the etype list here as well? What if the tgt
816 session key is DES3 and we want a ticket with a (say)
817 CAST session key. Should the DES3 etype be added to the
818 etype list, even if we don't want a session key with
819 DES3? */
822 krb5_encrypt_EncryptedData(context,
823 buf + sizeof(buf) - len, len,
824 etype, /* XXX */
826 &tgt->key,
827 &rep.enc_part);
829 ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
830 if(ret){
831 kdc_log(0, "Failed to encode TGS-REP: %s",
832 krb5_get_err_text(context, ret));
833 goto out;
835 krb5_data_copy(reply, buf + sizeof(buf) - len, len);
836 out:
837 free_TGS_REP(&rep);
838 if(et.starttime)
839 free(et.starttime);
840 if(et.renew_till)
841 free(et.renew_till);
842 free_LastReq(&ek.last_req);
843 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
844 free_EncryptionKey(&et.key);
846 return ret;
849 static krb5_error_code
850 tgs_check_authenticator(krb5_auth_context ac,
851 KDC_REQ_BODY *b, krb5_keyblock *key)
853 krb5_authenticator auth;
854 size_t len;
855 unsigned char buf[1024];
856 krb5_error_code ret;
858 krb5_auth_getauthenticator(context, ac, &auth);
859 if(auth->cksum == NULL){
860 kdc_log(0, "No authenticator in request");
861 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
862 goto out;
864 /* XXX */
865 if (auth->cksum->cksumtype != CKSUMTYPE_RSA_MD4 &&
866 auth->cksum->cksumtype != CKSUMTYPE_RSA_MD5 &&
867 auth->cksum->cksumtype != CKSUMTYPE_RSA_MD5_DES){
868 kdc_log(0, "Bad checksum type in authenticator: %d",
869 auth->cksum->cksumtype);
870 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
871 goto out;
874 /* XXX */
875 ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf),
876 b, &len);
877 if(ret){
878 kdc_log(0, "Failed to encode KDC-REQ-BODY: %s",
879 krb5_get_err_text(context, ret));
880 goto out;
882 ret = krb5_verify_checksum(context, buf + sizeof(buf) - len, len,
883 key,
884 auth->cksum);
885 if(ret){
886 kdc_log(0, "Failed to verify checksum: %s",
887 krb5_get_err_text(context, ret));
889 out:
890 free_Authenticator(auth);
891 free(auth);
892 return ret;
897 static krb5_error_code
898 tgs_rep2(KDC_REQ_BODY *b,
899 krb5_principal sp,
900 PA_DATA *pa_data,
901 krb5_data *reply,
902 const char *from)
904 krb5_ap_req ap_req;
905 size_t len;
906 krb5_error_code ret;
907 krb5_principal princ;
908 krb5_auth_context ac = NULL;
909 krb5_ticket *ticket = NULL;
910 krb5_flags ap_req_options;
911 const char *e_text = NULL;
913 hdb_entry *krbtgt;
914 EncTicketPart *tgt;
915 Key *ekey;
916 krb5_principal cp = NULL;
918 memset(&ap_req, 0, sizeof(ap_req));
919 ret = krb5_decode_ap_req(context, &pa_data->padata_value, &ap_req);
920 if(ret){
921 kdc_log(0, "Failed to decode AP-REQ: %s",
922 krb5_get_err_text(context, ret));
923 goto out2;
926 if(ap_req.ticket.sname.name_string.len != 2 ||
927 strcmp(ap_req.ticket.sname.name_string.val[0], "krbtgt")){
928 kdc_log(0, "PA-DATA is not a ticket-granting ticket");
929 ret = KRB5KDC_ERR_POLICY; /* ? */
930 goto out2;
933 principalname2krb5_principal(&princ,
934 ap_req.ticket.sname,
935 ap_req.ticket.realm);
937 krbtgt = db_fetch(princ);
939 if(krbtgt == NULL) {
940 char *p;
941 krb5_unparse_name(context, princ, &p);
942 kdc_log(0, "Ticket-granting ticket not found in database: %s", p);
943 free(p);
944 ret = KRB5KRB_AP_ERR_NOT_US;
945 goto out2;
948 ekey = unseal_key(&krbtgt->keys.val[0]); /* XXX */
949 ret = krb5_verify_ap_req(context,
950 &ac,
951 &ap_req,
952 princ,
953 &ekey->key,
954 &ap_req_options,
955 &ticket);
956 hdb_free_key(ekey);
958 krb5_free_principal(context, princ);
959 if(ret) {
960 kdc_log(0, "Failed to verify AP-REQ: %s",
961 krb5_get_err_text(context, ret));
962 goto out2;
965 tgt = &ticket->ticket;
967 ret = tgs_check_authenticator(ac, b, &tgt->key);
969 krb5_auth_con_free(context, ac);
971 if(ret){
972 kdc_log(0, "Failed to verify authenticator: %s",
973 krb5_get_err_text(context, ret));
974 goto out2;
978 PrincipalName *s;
979 Realm r;
980 char *spn = NULL, *cpn = NULL;
981 hdb_entry *server = NULL, *client = NULL;
983 s = b->sname;
984 r = b->realm;
985 if(s == NULL)
986 if(b->kdc_options.enc_tkt_in_skey &&
987 b->additional_tickets &&
988 b->additional_tickets->len >= 1){
989 krb5_principal p;
990 hdb_entry *uu;
991 principalname2krb5_principal(&p,
992 b->additional_tickets->val[0].sname,
993 b->additional_tickets->val[0].realm);
994 uu = db_fetch(p);
995 krb5_free_principal(context, p);
996 if(uu == NULL){
997 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
998 goto out;
1000 /* XXX */
1001 }else{
1002 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1003 goto out;
1006 #if 0
1007 principalname2krb5_principal(&sp, *s, r);
1008 #endif
1009 krb5_unparse_name(context, sp, &spn);
1010 server = db_fetch(sp);
1012 principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1013 krb5_unparse_name(context, cp, &cpn);
1014 client = db_fetch(cp);
1016 kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1018 if(server == NULL){
1019 kdc_log(0, "Server not found in database: %s", spn);
1020 /* do foreign realm stuff */
1021 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1022 goto out;
1025 if(client == NULL){
1026 kdc_log(0, "Client not found in database: %s", cpn);
1027 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1028 goto out;
1031 if((b->kdc_options.validate || b->kdc_options.renew) &&
1032 !krb5_principal_compare(context,
1033 krbtgt->principal,
1034 server->principal)){
1035 kdc_log(0, "Inconsistent request.");
1036 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1037 goto out;
1040 ret = tgs_make_reply(b, tgt, server, client, reply);
1042 out:
1043 free(spn);
1044 free(cpn);
1046 if(server){
1047 hdb_free_entry(context, server);
1048 free(server);
1050 if(client){
1051 hdb_free_entry(context, client);
1052 free(client);
1056 out2:
1057 if(ret)
1058 krb5_mk_error(context,
1059 ret,
1060 e_text,
1061 NULL,
1065 reply);
1066 krb5_free_principal(context, cp);
1067 if (ticket) {
1068 krb5_free_ticket(context, ticket);
1069 free(ticket);
1071 free_AP_REQ(&ap_req);
1073 if(krbtgt){
1074 hdb_free_entry(context, krbtgt);
1075 free(krbtgt);
1077 return ret;
1080 static krb5_error_code
1081 request_server(KDC_REQ *req, krb5_principal *server)
1083 PrincipalName *s = NULL;
1084 Realm r;
1085 s = req->req_body.sname;
1086 r = req->req_body.realm;
1087 if(s == NULL &&
1088 req->req_body.additional_tickets &&
1089 req->req_body.additional_tickets->len){
1090 s = &req->req_body.additional_tickets->val[0].sname;
1091 r = req->req_body.additional_tickets->val[0].realm;
1093 if(s)
1094 principalname2krb5_principal(server, *s, r);
1095 else
1096 krb5_build_principal(context, server, strlen(r), r, "anonymous", NULL);
1097 return 0;
1101 krb5_error_code
1102 tgs_rep(KDC_REQ *req,
1103 krb5_data *data,
1104 const char *from)
1106 krb5_error_code ret;
1107 int i;
1108 PA_DATA *pa_data = NULL;
1109 krb5_principal server;
1111 request_server(req, &server);
1113 if(req->padata == NULL){
1114 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1115 kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1116 goto out;
1119 for(i = 0; i < req->padata->len; i++)
1120 if(req->padata->val[i].padata_type == pa_tgs_req){
1121 pa_data = &req->padata->val[i];
1122 break;
1124 if(pa_data == NULL){
1125 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1127 kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1128 goto out;
1130 ret = tgs_rep2(&req->req_body, server, pa_data, data, from);
1131 out:
1132 if(ret && data->data == NULL)
1133 krb5_mk_error(context,
1134 ret,
1135 NULL,
1136 NULL,
1137 NULL,
1138 server,
1140 data);
1141 krb5_free_principal(context, server);
1142 return ret;