Add des3 string-to-key. Add ktype argument to krb5_string_to_key().
[heimdal.git] / kdc / kerberos5.c
blob15eb32d7b250a4ef2b9526e39c8cb73f33f9db02
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 static void
56 set_salt_padata (METHOD_DATA **m, Salt *salt)
58 if (salt) {
59 ALLOC(*m);
60 (*m)->len = 1;
61 ALLOC((*m)->val);
62 (*m)->val->padata_type = salt->type;
63 copy_octet_string(&salt->salt,
64 &(*m)->val->padata_value);
68 krb5_error_code
69 as_rep(KDC_REQ *req,
70 krb5_data *reply,
71 const char *from)
73 KDC_REQ_BODY *b = &req->req_body;
74 AS_REP rep;
75 KDCOptions f = b->kdc_options;
76 hdb_entry *client = NULL, *server = NULL;
77 int etype;
78 EncTicketPart et;
79 EncKDCRepPart ek;
80 krb5_principal client_princ, server_princ;
81 char *client_name, *server_name;
82 krb5_error_code ret = 0;
83 const char *e_text = NULL;
84 int i;
86 Key *ckey, *skey, *ekey;
88 if(b->sname == NULL){
89 server_name = "<unknown server>";
90 ret = KRB5KRB_ERR_GENERIC;
91 e_text = "No server in request";
92 } else{
93 principalname2krb5_principal (&server_princ, *(b->sname), b->realm);
94 krb5_unparse_name(context, server_princ, &server_name);
97 if(b->cname == NULL){
98 client_name = "<unknown client>";
99 ret = KRB5KRB_ERR_GENERIC;
100 e_text = "No client in request";
101 } else {
102 principalname2krb5_principal (&client_princ, *(b->cname), b->realm);
103 krb5_unparse_name(context, client_princ, &client_name);
105 kdc_log(0, "AS-REQ %s from %s for %s",
106 client_name, from, server_name);
108 if(ret)
109 goto out;
111 client = db_fetch(client_princ);
112 if(client == NULL){
113 kdc_log(0, "UNKNOWN -- %s", client_name);
114 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
115 goto out;
118 if (client->valid_start && *client->valid_start > kdc_time) {
119 kdc_log(0, "Client not yet valid -- %s", client_name);
120 ret = KRB5KDC_ERR_CLIENT_NOTYET;
121 goto out;
124 if (client->valid_end && *client->valid_end < kdc_time) {
125 kdc_log(0, "Client expired -- %s", client_name);
126 ret = KRB5KDC_ERR_NAME_EXP;
127 goto out;
130 server = db_fetch(server_princ);
132 if(server == NULL){
133 kdc_log(0, "UNKNOWN -- %s", server_name);
134 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
135 goto out;
138 if (server->valid_start && *server->valid_start > kdc_time) {
139 kdc_log(0, "Server not yet valid -- %s", server_name);
140 ret = KRB5KDC_ERR_SERVICE_NOTYET;
141 goto out;
144 if (server->valid_end && *server->valid_end < kdc_time) {
145 kdc_log(0, "Server expired -- %s", server_name);
146 ret = KRB5KDC_ERR_SERVICE_EXP;
147 goto out;
150 if(!client->flags.client){
151 ret = KRB5KDC_ERR_POLICY;
152 kdc_log(0, "Principal may not act as client -- %s",
153 client_name);
154 goto out;
156 if(!server->flags.server){
157 ret = KRB5KDC_ERR_POLICY;
158 kdc_log(0, "Principal (%s) may not act as server -- %s",
159 server_name, client_name);
160 goto out;
163 if (client->flags.invalid) {
164 ret = KRB5KDC_ERR_POLICY;
165 kdc_log(0, "Client (%s) has invalid bit set", client_name);
166 goto out;
169 if (server->flags.invalid) {
170 ret = KRB5KDC_ERR_POLICY;
171 kdc_log(0, "Server (%s) has invalid bit set", server_name);
172 goto out;
175 if (client->pw_end && *client->pw_end < kdc_time
176 && !server->flags.change_pw) {
177 ret = KRB5KDC_ERR_KEY_EXPIRED;
178 kdc_log(0, "Client (%s)'s key has expired", client_name);
179 goto out;
182 /* Find appropriate key */
183 for(i = 0; i < b->etype.len; i++){
184 ret = hdb_etype2key(context, client, b->etype.val[i], &ckey);
185 if(ret)
186 continue;
187 ret = hdb_etype2key(context, server, b->etype.val[i], &skey);
188 if(ret)
189 continue;
190 break;
193 if(ret){
194 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
195 kdc_log(0, "No support for etypes -- %s", client_name);
196 goto out;
199 etype = b->etype.val[i];
201 memset(&et, 0, sizeof(et));
202 memset(&ek, 0, sizeof(ek));
204 if(req->padata){
205 int i;
206 PA_DATA *pa;
207 int found_pa = 0;
208 kdc_log(5, "Looking for pa-data -- %s", client_name);
209 for(i = 0; i < req->padata->len; i++){
210 PA_DATA *pa = &req->padata->val[i];
211 if(pa->padata_type == pa_enc_timestamp){
212 krb5_data ts_data;
213 PA_ENC_TS_ENC p;
214 time_t patime;
215 size_t len;
216 EncryptedData enc_data;
218 kdc_log(5, "Found pa-enc-timestamp -- %s",
219 client_name);
220 found_pa = 1;
222 ret = decode_EncryptedData(pa->padata_value.data,
223 pa->padata_value.length,
224 &enc_data,
225 &len);
226 if (ret) {
227 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
228 kdc_log(5, "Failed to decode PA-DATA -- %s",
229 client_name);
230 goto out;
233 ekey = unseal_key(ckey);
235 ret = krb5_decrypt (context,
236 enc_data.cipher.data,
237 enc_data.cipher.length,
238 enc_data.etype,
239 &ekey->key,
240 &ts_data);
241 hdb_free_key(ekey);
242 free_EncryptedData(&enc_data);
243 if(ret){
244 e_text = "Failed to decrypt PA-DATA";
245 kdc_log (5, "Failed to decrypt PA-DATA -- %s",
246 client_name);
247 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
248 continue;
250 ret = decode_PA_ENC_TS_ENC(ts_data.data,
251 ts_data.length,
253 &len);
254 krb5_data_free(&ts_data);
255 if(ret){
256 e_text = "Failed to decode PA-ENC-TS-ENC";
257 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
258 kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s",
259 client_name);
260 continue;
262 patime = p.patimestamp;
263 free_PA_ENC_TS_ENC(&p);
264 if (abs(kdc_time - p.patimestamp) > context->max_skew) {
265 ret = KRB5KDC_ERR_PREAUTH_FAILED;
266 krb5_mk_error (context,
267 ret,
268 "Too large time skew",
269 NULL,
270 client_princ,
271 server_princ,
273 reply);
274 kdc_log(0, "Too large time skew -- %s",
275 client_name);
276 goto out2;
278 et.flags.pre_authent = 1;
279 kdc_log(2, "Pre-authentication succeded -- %s",
280 client_name);
281 break;
282 } else {
283 kdc_log(5, "Found pa-data of type %d -- %s",
284 pa->padata_type, client_name);
287 /* XXX */
288 if(found_pa == 0 && require_preauth)
289 goto use_pa;
290 /* We come here if we found a pa-enc-timestamp, but if there
291 was some problem with it, other than too large skew */
292 if(et.flags.pre_authent == 0){
293 kdc_log(0, "%s -- %s", e_text, client_name);
294 e_text = NULL;
295 goto out;
297 }else if (require_preauth
298 || client->flags.require_preauth) {
299 METHOD_DATA method_data;
300 PA_DATA pa_data;
301 u_char buf[16];
302 size_t len;
303 krb5_data foo_data;
305 use_pa:
306 method_data.len = 1;
307 method_data.val = &pa_data;
309 pa_data.padata_type = pa_enc_timestamp;
310 pa_data.padata_value.length = 0;
311 pa_data.padata_value.data = NULL;
313 encode_METHOD_DATA(buf + sizeof(buf) - 1,
314 sizeof(buf),
315 &method_data,
316 &len);
317 foo_data.length = len;
318 foo_data.data = buf + sizeof(buf) - len;
320 ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
321 krb5_mk_error(context,
322 ret,
323 "Need to use PA-ENC-TIMESTAMP",
324 &foo_data,
325 client_princ,
326 server_princ,
328 reply);
330 kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name);
331 goto out2;
334 kdc_log(2, "Using etype %d -- %s", etype, client_name);
336 memset(&rep, 0, sizeof(rep));
337 rep.pvno = 5;
338 rep.msg_type = krb_as_rep;
339 copy_Realm(&b->realm, &rep.crealm);
340 copy_PrincipalName(b->cname, &rep.cname);
341 rep.ticket.tkt_vno = 5;
342 copy_Realm(&b->realm, &rep.ticket.realm);
343 copy_PrincipalName(b->sname, &rep.ticket.sname);
345 if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey){
346 ret = KRB5KDC_ERR_BADOPTION;
347 kdc_log(0, "Bad KDC options -- %s", client_name);
348 goto out;
351 et.flags.initial = 1;
352 if(client->flags.forwardable && server->flags.forwardable)
353 et.flags.forwardable = f.forwardable;
354 else if (f.forwardable) {
355 ret = KRB5KDC_ERR_POLICY;
356 kdc_log(0, "Ticket may not be forwardable -- %s", client_name);
357 goto out;
359 if(client->flags.proxiable && server->flags.proxiable)
360 et.flags.proxiable = f.proxiable;
361 else if (f.proxiable) {
362 ret = KRB5KDC_ERR_POLICY;
363 kdc_log(0, "Ticket may not be proxiable -- %s", client_name);
364 goto out;
366 if(client->flags.postdate && server->flags.postdate)
367 et.flags.may_postdate = f.allow_postdate;
368 else if (f.allow_postdate){
369 ret = KRB5KDC_ERR_POLICY;
370 kdc_log(0, "Ticket may not be postdatable -- %s", client_name);
371 goto out;
374 krb5_generate_random_keyblock(context, ckey->key.keytype, &et.key);
375 copy_PrincipalName(b->cname, &et.cname);
376 copy_Realm(&b->realm, &et.crealm);
379 time_t start;
380 time_t t;
382 start = et.authtime = kdc_time;
384 if(f.postdated && req->req_body.from){
385 ALLOC(et.starttime);
386 start = *et.starttime = *req->req_body.from;
387 et.flags.invalid = 1;
388 et.flags.postdated = 1; /* XXX ??? */
389 kdc_log(2, "Postdated ticket requested -- %s",
390 client_name);
392 fix_time(&b->till);
393 t = *b->till;
394 if(client->max_life)
395 t = min(t, start + *client->max_life);
396 if(server->max_life)
397 t = min(t, start + *server->max_life);
398 #if 0
399 t = min(t, start + realm->max_life);
400 #endif
401 et.endtime = t;
402 if(f.renewable_ok && et.endtime < *b->till){
403 f.renewable = 1;
404 if(b->rtime == NULL){
405 ALLOC(b->rtime);
406 *b->rtime = 0;
408 if(*b->rtime < *b->till)
409 *b->rtime = *b->till;
411 if(f.renewable && b->rtime){
412 t = *b->rtime;
413 if(t == 0)
414 t = MAX_TIME;
415 if(client->max_renew)
416 t = min(t, start + *client->max_renew);
417 if(server->max_renew)
418 t = min(t, start + *server->max_renew);
419 #if 0
420 t = min(t, start + realm->max_renew);
421 #endif
422 ALLOC(et.renew_till);
423 *et.renew_till = t;
424 et.flags.renewable = 1;
428 if(b->addresses){
429 ALLOC(et.caddr);
430 copy_HostAddresses(b->addresses, et.caddr);
433 copy_EncryptionKey(&et.key, &ek.key);
435 /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded
436 * as 0 and as 0x80 (meaning indefinite length) apart, and is thus
437 * incapable to correctly decode vectors of zero length.
439 * To fix this, always send at least one no-op last_req
441 * If there's a pw_end or valid_end we will use that,
442 * otherwise just a dummy lr.
444 ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val));
445 ek.last_req.len = 0;
446 if (client->pw_end
447 && (kdc_warn_pwexpire == 0
448 || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) {
449 ek.last_req.val[ek.last_req.len].lr_type = 6;
450 ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end;
451 ++ek.last_req.len;
453 if (client->valid_end) {
454 ek.last_req.val[ek.last_req.len].lr_type = 7;
455 ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end;
456 ++ek.last_req.len;
458 if (ek.last_req.len == 0) {
459 ek.last_req.val[ek.last_req.len].lr_type = 0;
460 ek.last_req.val[ek.last_req.len].lr_value = 0;
461 ++ek.last_req.len;
463 ek.nonce = b->nonce;
464 if (client->valid_end || client->pw_end) {
465 ALLOC(ek.key_expiration);
466 if (client->valid_end)
467 if (client->pw_end)
468 *ek.key_expiration = min(*client->valid_end, *client->pw_end);
469 else
470 *ek.key_expiration = *client->valid_end;
471 else
472 *ek.key_expiration = *client->pw_end;
473 } else
474 ek.key_expiration = NULL;
475 ek.flags = et.flags;
476 ek.authtime = et.authtime;
477 if (et.starttime) {
478 ALLOC(ek.starttime);
479 *ek.starttime = *et.starttime;
480 } else
481 ek.starttime = et.starttime;
482 ek.endtime = et.endtime;
483 if (et.renew_till) {
484 ALLOC(ek.renew_till);
485 *ek.renew_till = *et.renew_till;
486 } else
487 ek.renew_till = et.renew_till;
488 copy_Realm(&rep.ticket.realm, &ek.srealm);
489 copy_PrincipalName(&rep.ticket.sname, &ek.sname);
490 if(et.caddr){
491 ALLOC(ek.caddr);
492 copy_HostAddresses(et.caddr, ek.caddr);
496 unsigned char buf[8192]; /* XXX The data could be indefinite */
497 size_t len;
499 ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf),
500 &et, &len);
501 free_EncTicketPart(&et);
502 if(ret) {
503 kdc_log(0, "Failed to encode ticket -- %s", client);
504 goto out;
507 ekey = unseal_key(skey);
508 krb5_encrypt_EncryptedData(context,
509 buf + sizeof(buf) - len,
510 len,
511 etype,
512 server->kvno,
513 &ekey->key,
514 &rep.ticket.enc_part);
515 hdb_free_key(ekey);
517 ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf),
518 &ek, &len);
519 free_EncKDCRepPart(&ek);
520 if(ret) {
521 kdc_log(0, "Failed to encode KDC-REP -- %s", client_name);
522 goto out;
524 ekey = unseal_key(ckey);
525 krb5_encrypt_EncryptedData(context,
526 buf + sizeof(buf) - len,
527 len,
528 etype,
529 client->kvno,
530 &ekey->key,
531 &rep.enc_part);
532 hdb_free_key(ekey);
533 set_salt_padata (&rep.padata, ckey->salt);
535 ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
536 free_AS_REP(&rep);
537 if(ret) {
538 kdc_log(0, "Failed to encode AS-REP -- %s", client_name);
539 goto out;
542 krb5_data_copy(reply, buf + sizeof(buf) - len, len);
544 out:
545 if(ret){
546 krb5_mk_error(context,
547 ret,
548 e_text,
549 NULL,
550 client_princ,
551 server_princ,
553 reply);
555 out2:
556 krb5_free_principal(context, client_princ);
557 free(client_name);
558 krb5_free_principal(context, server_princ);
559 free(server_name);
560 if(client){
561 hdb_free_entry(context, client);
562 free(client);
564 if(server){
565 hdb_free_entry(context, server);
566 free(server);
569 return ret;
573 static krb5_error_code
574 check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et)
576 KDCOptions f = b->kdc_options;
578 if(f.validate){
579 if(!tgt->flags.invalid || tgt->starttime == NULL){
580 kdc_log(0, "Bad request to validate ticket");
581 return KRB5KDC_ERR_BADOPTION;
583 if(*tgt->starttime < kdc_time){
584 kdc_log(0, "Early request to validate ticket");
585 return KRB5KRB_AP_ERR_TKT_NYV;
587 /* XXX tkt = tgt */
588 et->flags.invalid = 0;
589 }else if(tgt->flags.invalid){
590 kdc_log(0, "Ticket-granting ticket has INVALID flag set");
591 return KRB5KRB_AP_ERR_TKT_INVALID;
594 if(f.forwardable){
595 if(!tgt->flags.forwardable){
596 kdc_log(0, "Bad request for forwardable ticket");
597 return KRB5KDC_ERR_BADOPTION;
599 et->flags.forwardable = 1;
601 if(f.forwarded){
602 if(!tgt->flags.forwardable){
603 kdc_log(0, "Request to forward non-forwardable ticket");
604 return KRB5KDC_ERR_BADOPTION;
606 et->flags.forwarded = 1;
607 et->caddr = b->addresses;
609 if(tgt->flags.forwarded)
610 et->flags.forwarded = 1;
612 if(f.proxiable){
613 if(!tgt->flags.proxiable){
614 kdc_log(0, "Bad request for proxiable ticket");
615 return KRB5KDC_ERR_BADOPTION;
617 et->flags.proxiable = 1;
619 if(f.proxy){
620 if(!tgt->flags.proxiable){
621 kdc_log(0, "Request to proxy non-proxiable ticket");
622 return KRB5KDC_ERR_BADOPTION;
624 et->flags.proxy = 1;
625 et->caddr = b->addresses;
627 if(tgt->flags.proxy)
628 et->flags.proxy = 1;
630 if(f.allow_postdate){
631 if(!tgt->flags.may_postdate){
632 kdc_log(0, "Bad request for post-datable ticket");
633 return KRB5KDC_ERR_BADOPTION;
635 et->flags.may_postdate = 1;
637 if(f.postdated){
638 if(!tgt->flags.may_postdate){
639 kdc_log(0, "Bad request for postdated ticket");
640 return KRB5KDC_ERR_BADOPTION;
642 if(b->from)
643 *et->starttime = *b->from;
644 et->flags.postdated = 1;
645 et->flags.invalid = 1;
646 }else if(b->from && *b->from > kdc_time + context->max_skew){
647 kdc_log(0, "Ticket cannot be postdated");
648 return KRB5KDC_ERR_CANNOT_POSTDATE;
651 if(f.renewable){
652 if(!tgt->flags.renewable){
653 kdc_log(0, "Bad request for renewable ticket");
654 return KRB5KDC_ERR_BADOPTION;
656 et->flags.renewable = 1;
657 ALLOC(et->renew_till);
658 *et->renew_till = *b->rtime;
660 if(f.renew){
661 time_t old_life;
662 if(!tgt->flags.renewable || tgt->renew_till == NULL){
663 kdc_log(0, "Request to renew non-renewable ticket");
664 return KRB5KDC_ERR_BADOPTION;
666 old_life = tgt->endtime;
667 if(tgt->starttime)
668 old_life -= *tgt->starttime;
669 else
670 old_life -= tgt->authtime;
671 et->endtime = *et->starttime + old_life;
674 /* check for excess flags */
675 return 0;
678 static krb5_error_code
679 fix_transited_encoding(TransitedEncoding *tr,
680 const char *client_realm,
681 const char *server_realm,
682 const char *tgt_realm)
684 krb5_error_code ret = 0;
685 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)){
686 char **realms = NULL, **tmp;
687 int num_realms = 0;
688 int i;
689 if(tr->tr_type){
690 if(tr->tr_type != DOMAIN_X500_COMPRESS){
691 kdc_log(0, "Unknown transited type: %u",
692 tr->tr_type);
693 return KRB5KDC_ERR_TRTYPE_NOSUPP;
695 ret = krb5_domain_x500_decode(tr->contents,
696 &realms,
697 &num_realms,
698 client_realm,
699 server_realm);
700 if(ret){
701 krb5_warn(context, ret, "Decoding transited encoding");
702 return ret;
705 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
706 if(tmp == NULL){
707 ret = ENOMEM;
708 goto free_realms;
710 realms = tmp;
711 realms[num_realms] = strdup(tgt_realm);
712 if(realms[num_realms] == NULL){
713 ret = ENOMEM;
714 goto free_realms;
716 num_realms++;
717 free_TransitedEncoding(tr);
718 tr->tr_type = DOMAIN_X500_COMPRESS;
719 ret = krb5_domain_x500_encode(realms, num_realms, &tr->contents);
720 if(ret)
721 krb5_warn(context, ret, "Encoding transited encoding");
722 free_realms:
723 for(i = 0; i < num_realms; i++)
724 free(realms[i]);
725 free(realms);
727 return ret;
731 static krb5_error_code
732 tgs_make_reply(KDC_REQ_BODY *b, EncTicketPart *tgt,
733 hdb_entry *server, hdb_entry *client,
734 krb5_principal client_principal,
735 hdb_entry *krbtgt,
736 krb5_data *reply)
738 KDC_REP rep;
739 EncKDCRepPart ek;
740 EncTicketPart et;
741 KDCOptions f = b->kdc_options;
742 krb5_error_code ret;
743 int i;
744 krb5_enctype etype;
745 Key *skey, *ekey;
747 /* Find appropriate key */
748 for(i = 0; i < b->etype.len; i++){
749 ret = hdb_etype2key(context, server, b->etype.val[i], &skey);
750 if(ret == 0)
751 break;
754 if(ret){
755 kdc_log(0, "Failed to find requested etype");
756 return KRB5KDC_ERR_ETYPE_NOSUPP;
759 etype = b->etype.val[i];
761 memset(&rep, 0, sizeof(rep));
762 memset(&et, 0, sizeof(et));
763 memset(&ek, 0, sizeof(ek));
765 rep.pvno = 5;
766 rep.msg_type = krb_tgs_rep;
768 et.authtime = tgt->authtime;
769 fix_time(&b->till);
770 et.endtime = min(tgt->endtime, *b->till);
771 ALLOC(et.starttime);
772 *et.starttime = kdc_time;
774 ret = check_tgs_flags(b, tgt, &et);
775 if(ret)
776 return ret;
778 copy_TransitedEncoding(&tgt->transited, &et.transited);
779 ret = fix_transited_encoding(&et.transited,
780 *krb5_princ_realm(context, client_principal),
781 *krb5_princ_realm(context, server->principal),
782 *krb5_princ_realm(context, krbtgt->principal));
783 if(ret){
784 free_TransitedEncoding(&et.transited);
785 return ret;
789 copy_Realm(krb5_princ_realm(context, server->principal),
790 &rep.ticket.realm);
791 krb5_principal2principalname(&rep.ticket.sname, server->principal);
792 copy_Realm(&tgt->crealm, &rep.crealm);
793 copy_PrincipalName(&tgt->cname, &rep.cname);
794 rep.ticket.tkt_vno = 5;
796 ek.caddr = et.caddr;
797 if(et.caddr == NULL)
798 et.caddr = tgt->caddr;
801 time_t life;
802 life = et.endtime - *et.starttime;
803 if(client && client->max_life)
804 life = min(life, *client->max_life);
805 if(server->max_life)
806 life = min(life, *server->max_life);
807 et.endtime = *et.starttime + life;
809 if(f.renewable_ok && tgt->flags.renewable &&
810 et.renew_till == NULL && et.endtime < *b->till){
811 et.flags.renewable = 1;
812 ALLOC(et.renew_till);
813 *et.renew_till = *b->till;
815 if(et.renew_till){
816 time_t renew;
817 renew = *et.renew_till - et.authtime;
818 if(client && client->max_renew)
819 renew = min(renew, *client->max_renew);
820 if(server->max_renew)
821 renew = min(renew, *server->max_renew);
822 *et.renew_till = et.authtime + renew;
825 if(et.renew_till){
826 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
827 *et.starttime = min(*et.starttime, *et.renew_till);
828 et.endtime = min(et.endtime, *et.renew_till);
831 *et.starttime = min(*et.starttime, et.endtime);
833 if(*et.starttime == et.endtime){
834 ret = KRB5KDC_ERR_NEVER_VALID;
835 goto out;
837 if(et.renew_till && et.endtime == *et.renew_till){
838 free(et.renew_till);
839 et.renew_till = NULL;
840 et.flags.renewable = 0;
843 et.flags.pre_authent = tgt->flags.pre_authent;
844 et.flags.hw_authent = tgt->flags.hw_authent;
846 /* XXX Check enc-authorization-data */
848 krb5_generate_random_keyblock(context,
849 skey->key.keytype,
850 &et.key);
851 et.crealm = tgt->crealm;
852 et.cname = tgt->cname;
854 ek.key = et.key;
855 /* MIT must have at least one last_req */
856 ek.last_req.len = 1;
857 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
858 ek.nonce = b->nonce;
859 ek.flags = et.flags;
860 ek.authtime = et.authtime;
861 ek.starttime = et.starttime;
862 ek.endtime = et.endtime;
863 ek.renew_till = et.renew_till;
864 ek.srealm = rep.ticket.realm;
865 ek.sname = rep.ticket.sname;
869 unsigned char buf[8192]; /* XXX The data could be indefinite */
870 size_t len;
871 ret = encode_EncTicketPart(buf + sizeof(buf) - 1,
872 sizeof(buf), &et, &len);
873 if(ret){
874 kdc_log(0, "Failed to encode EncTicketPart: %s",
875 krb5_get_err_text(context, ret));
876 goto out;
878 ekey = unseal_key(skey);
879 krb5_encrypt_EncryptedData(context, buf + sizeof(buf) - len, len,
880 etype,
881 server->kvno,
882 &ekey->key,
883 &rep.ticket.enc_part);
884 hdb_free_key(ekey);
886 ret = encode_EncTGSRepPart(buf + sizeof(buf) - 1,
887 sizeof(buf), &ek, &len);
888 if(ret){
889 kdc_log(0, "Failed to encode EncTicketPart: %s",
890 krb5_get_err_text(context, ret));
891 goto out;
894 /* It is somewhat unclear where the etype in the following
895 encryption should come from. What we have is a session
896 key in the passed tgt, and a list of preferred etypes
897 *for the new ticket*. Should we pick the best possible
898 etype, given the keytype in the tgt, or should we look
899 at the etype list here as well? What if the tgt
900 session key is DES3 and we want a ticket with a (say)
901 CAST session key. Should the DES3 etype be added to the
902 etype list, even if we don't want a session key with
903 DES3? */
906 krb5_encrypt_EncryptedData(context,
907 buf + sizeof(buf) - len, len,
908 etype, /* XXX */
910 &tgt->key,
911 &rep.enc_part);
913 ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), &rep, &len);
914 if(ret){
915 kdc_log(0, "Failed to encode TGS-REP: %s",
916 krb5_get_err_text(context, ret));
917 goto out;
919 krb5_data_copy(reply, buf + sizeof(buf) - len, len);
920 out:
921 free_TGS_REP(&rep);
922 free_TransitedEncoding(&et.transited);
923 if(et.starttime)
924 free(et.starttime);
925 if(et.renew_till)
926 free(et.renew_till);
927 free_LastReq(&ek.last_req);
928 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
929 free_EncryptionKey(&et.key);
931 return ret;
934 static krb5_error_code
935 tgs_check_authenticator(krb5_auth_context ac,
936 KDC_REQ_BODY *b, krb5_keyblock *key)
938 krb5_authenticator auth;
939 size_t len;
940 unsigned char buf[8192];
941 krb5_error_code ret;
943 krb5_auth_getauthenticator(context, ac, &auth);
944 if(auth->cksum == NULL){
945 kdc_log(0, "No authenticator in request");
946 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
947 goto out;
949 /* XXX */
950 if (auth->cksum->cksumtype != CKSUMTYPE_RSA_MD4 &&
951 auth->cksum->cksumtype != CKSUMTYPE_RSA_MD5 &&
952 auth->cksum->cksumtype != CKSUMTYPE_RSA_MD5_DES){
953 kdc_log(0, "Bad checksum type in authenticator: %d",
954 auth->cksum->cksumtype);
955 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
956 goto out;
959 /* XXX */
960 ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf),
961 b, &len);
962 if(ret){
963 kdc_log(0, "Failed to encode KDC-REQ-BODY: %s",
964 krb5_get_err_text(context, ret));
965 goto out;
967 ret = krb5_verify_checksum(context, buf + sizeof(buf) - len, len,
968 key,
969 auth->cksum);
970 if(ret){
971 kdc_log(0, "Failed to verify checksum: %s",
972 krb5_get_err_text(context, ret));
974 out:
975 free_Authenticator(auth);
976 free(auth);
977 return ret;
980 static Realm
981 is_krbtgt(PrincipalName *p)
983 if(p->name_string.len == 2 && strcmp(p->name_string.val[0], "krbtgt") == 0)
984 return p->name_string.val[1];
985 else
986 return NULL;
989 static Realm
990 find_rpath(Realm r)
992 const char *new_realm = krb5_config_get_string(context->cf,
993 "libdefaults",
994 "capath",
996 NULL);
997 return (Realm)new_realm;
1001 static krb5_error_code
1002 tgs_rep2(KDC_REQ_BODY *b,
1003 PA_DATA *pa_data,
1004 krb5_data *reply,
1005 const char *from)
1007 krb5_ap_req ap_req;
1008 size_t len;
1009 krb5_error_code ret;
1010 krb5_principal princ;
1011 krb5_auth_context ac = NULL;
1012 krb5_ticket *ticket = NULL;
1013 krb5_flags ap_req_options;
1014 const char *e_text = NULL;
1016 hdb_entry *krbtgt;
1017 EncTicketPart *tgt;
1018 Key *ekey;
1019 krb5_principal cp = NULL;
1020 krb5_principal sp = NULL;
1022 memset(&ap_req, 0, sizeof(ap_req));
1023 ret = krb5_decode_ap_req(context, &pa_data->padata_value, &ap_req);
1024 if(ret){
1025 kdc_log(0, "Failed to decode AP-REQ: %s",
1026 krb5_get_err_text(context, ret));
1027 goto out2;
1030 if(!is_krbtgt(&ap_req.ticket.sname)){
1031 kdc_log(0, "PA-DATA is not a ticket-granting ticket");
1032 ret = KRB5KDC_ERR_POLICY; /* ? */
1033 goto out2;
1036 principalname2krb5_principal(&princ,
1037 ap_req.ticket.sname,
1038 ap_req.ticket.realm);
1040 krbtgt = db_fetch(princ);
1042 if(krbtgt == NULL) {
1043 char *p;
1044 krb5_unparse_name(context, princ, &p);
1045 kdc_log(0, "Ticket-granting ticket not found in database: %s", p);
1046 free(p);
1047 ret = KRB5KRB_AP_ERR_NOT_US;
1048 goto out2;
1051 ekey = unseal_key(&krbtgt->keys.val[0]); /* XXX */
1052 ret = krb5_verify_ap_req(context,
1053 &ac,
1054 &ap_req,
1055 princ,
1056 &ekey->key,
1057 &ap_req_options,
1058 &ticket);
1059 hdb_free_key(ekey);
1061 krb5_free_principal(context, princ);
1062 if(ret) {
1063 kdc_log(0, "Failed to verify AP-REQ: %s",
1064 krb5_get_err_text(context, ret));
1065 goto out2;
1068 tgt = &ticket->ticket;
1070 ret = tgs_check_authenticator(ac, b, &tgt->key);
1072 krb5_auth_con_free(context, ac);
1074 if(ret){
1075 kdc_log(0, "Failed to verify authenticator: %s",
1076 krb5_get_err_text(context, ret));
1077 goto out2;
1081 PrincipalName *s;
1082 Realm r;
1083 char *spn = NULL, *cpn = NULL;
1084 hdb_entry *server = NULL, *client = NULL;
1085 TransitedEncoding tr;
1086 int loop = 0;
1088 s = b->sname;
1089 r = b->realm;
1091 if(s == NULL)
1092 if(b->kdc_options.enc_tkt_in_skey &&
1093 b->additional_tickets &&
1094 b->additional_tickets->len >= 1){
1095 krb5_principal p;
1096 hdb_entry *uu;
1097 principalname2krb5_principal(&p,
1098 b->additional_tickets->val[0].sname,
1099 b->additional_tickets->val[0].realm);
1100 uu = db_fetch(p);
1101 krb5_free_principal(context, p);
1102 if(uu == NULL){
1103 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1104 goto out;
1106 /* XXX */
1107 }else{
1108 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1109 goto out;
1112 principalname2krb5_principal(&sp, *s, r);
1113 krb5_unparse_name(context, sp, &spn);
1114 principalname2krb5_principal(&cp, tgt->cname, tgt->crealm);
1115 krb5_unparse_name(context, cp, &cpn);
1116 kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn);
1117 server_lookup:
1118 server = db_fetch(sp);
1121 if(server == NULL){
1122 Realm req_rlm, new_rlm;
1123 if(loop++ < 2 && (req_rlm = is_krbtgt(&sp->name))){
1124 new_rlm = find_rpath(req_rlm);
1125 if(new_rlm){
1126 kdc_log(5, "krbtgt for realm %s not found, trying %s",
1127 req_rlm, new_rlm);
1128 krb5_free_principal(context, sp);
1129 free(spn);
1130 krb5_make_principal(context, &sp, r,
1131 "krbtgt", new_rlm, NULL);
1132 krb5_unparse_name(context, sp, &spn);
1133 goto server_lookup;
1136 kdc_log(0, "Server not found in database: %s", spn);
1137 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1138 goto out;
1141 client = db_fetch(cp);
1142 if(client == NULL)
1143 kdc_log(1, "Client not found in database: %s", cpn);
1144 #if 0
1145 /* XXX check client only if same realm as krbtgt-instance */
1146 if(client == NULL){
1147 kdc_log(0, "Client not found in database: %s", cpn);
1148 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1149 goto out;
1151 #endif
1154 if((b->kdc_options.validate || b->kdc_options.renew) &&
1155 !krb5_principal_compare(context,
1156 krbtgt->principal,
1157 server->principal)){
1158 kdc_log(0, "Inconsistent request.");
1159 ret = KRB5KDC_ERR_SERVER_NOMATCH;
1160 goto out;
1163 ret = tgs_make_reply(b, tgt, server, client, cp, krbtgt, reply);
1165 out:
1166 free(spn);
1167 free(cpn);
1169 if(server){
1170 hdb_free_entry(context, server);
1171 free(server);
1173 if(client){
1174 hdb_free_entry(context, client);
1175 free(client);
1179 out2:
1180 if(ret)
1181 krb5_mk_error(context,
1182 ret,
1183 e_text,
1184 NULL,
1188 reply);
1189 krb5_free_principal(context, cp);
1190 krb5_free_principal(context, sp);
1191 if (ticket) {
1192 krb5_free_ticket(context, ticket);
1193 free(ticket);
1195 free_AP_REQ(&ap_req);
1197 if(krbtgt){
1198 hdb_free_entry(context, krbtgt);
1199 free(krbtgt);
1201 return ret;
1204 krb5_error_code
1205 tgs_rep(KDC_REQ *req,
1206 krb5_data *data,
1207 const char *from)
1209 krb5_error_code ret;
1210 int i;
1211 PA_DATA *pa_data = NULL;
1213 if(req->padata == NULL){
1214 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1215 kdc_log(0, "TGS-REQ from %s without PA-DATA", from);
1216 goto out;
1219 for(i = 0; i < req->padata->len; i++)
1220 if(req->padata->val[i].padata_type == pa_tgs_req){
1221 pa_data = &req->padata->val[i];
1222 break;
1224 if(pa_data == NULL){
1225 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1227 kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from);
1228 goto out;
1230 ret = tgs_rep2(&req->req_body, pa_data, data, from);
1231 out:
1232 if(ret && data->data == NULL)
1233 krb5_mk_error(context,
1234 ret,
1235 NULL,
1236 NULL,
1237 NULL,
1238 NULL,
1240 data);
1241 return ret;